Compare commits
1 Commits
developmen
...
fix/optimi
Author | SHA1 | Date | |
---|---|---|---|
|
51fd7a8fc1 |
10
.github/dependabot.yml
vendored
10
.github/dependabot.yml
vendored
@@ -1,10 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: saturday
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
||||
target-branch: developement
|
7
.github/release.yml
vendored
7
.github/release.yml
vendored
@@ -1,7 +0,0 @@
|
||||
changelog:
|
||||
exclude:
|
||||
labels:
|
||||
- internal
|
||||
authors:
|
||||
- dependabot
|
||||
- github-actions
|
40
.github/workflows/codeql-analysis.yml
vendored
40
.github/workflows/codeql-analysis.yml
vendored
@@ -1,40 +0,0 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- development
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- development
|
||||
schedule:
|
||||
- cron: '32 11 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
-
|
||||
name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
-
|
||||
name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: 'python'
|
||||
-
|
||||
name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
-
|
||||
name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
25
.github/workflows/stale.yml
vendored
25
.github/workflows/stale.yml
vendored
@@ -1,25 +0,0 @@
|
||||
name: Mark stale issues
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 * * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v4
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 30
|
||||
days-before-close: 5
|
||||
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Please comment or update this issue or it will be closed in 5 days.'
|
||||
stale-issue-label: 'stale'
|
||||
exempt-issue-labels: 'Internal, Fixed in next release, Bug: Confirmed, Documentation Needed'
|
||||
exempt-all-issue-assignees: true
|
||||
operations-per-run: 300
|
27
.github/workflows/sync-back-to-dev.yml
vendored
27
.github/workflows/sync-back-to-dev.yml
vendored
@@ -1,27 +0,0 @@
|
||||
name: Sync Back to Development
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
sync-branches:
|
||||
runs-on: ubuntu-latest
|
||||
name: Syncing branches
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Opening pull request
|
||||
id: pull
|
||||
uses: tretuna/sync-branches@1.4.0
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
FROM_BRANCH: 'master'
|
||||
TO_BRANCH: 'development'
|
||||
- name: Label the pull request to ignore for release note generation
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
labels: internal
|
||||
repo: ${{ github.repository }}
|
||||
number: ${{ steps.pull.outputs.PULL_REQUEST_NUMBER }}
|
48
.github/workflows/test.yml
vendored
48
.github/workflows/test.yml
vendored
@@ -1,48 +0,0 @@
|
||||
name: Test Supported Distributions
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
jobs:
|
||||
smoke-test:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Run Smoke Tests
|
||||
run: |
|
||||
# Ensure scripts in repository are executable
|
||||
IFS=$'\n';
|
||||
for f in $(find . -name '*.sh'); do if [[ ! -x $f ]]; then echo "$f is not executable" && FAIL=1; fi ;done
|
||||
unset IFS;
|
||||
# If FAIL is 1 then we fail.
|
||||
[[ $FAIL == 1 ]] && exit 1 || echo "Smoke Tests Passed"
|
||||
|
||||
distro-test:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
needs: smoke-test
|
||||
strategy:
|
||||
matrix:
|
||||
distro: [debian_9, debian_10, debian_11, ubuntu_16, ubuntu_18, ubuntu_20, ubuntu_21, centos_7, centos_8, fedora_33, fedora_34]
|
||||
env:
|
||||
DISTRO: ${{matrix.distro}}
|
||||
steps:
|
||||
-
|
||||
name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Set up Python 3.8
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: 3.8
|
||||
-
|
||||
name: Install dependencies
|
||||
run: pip install -r test/requirements.txt
|
||||
-
|
||||
name: Test with tox
|
||||
run: tox -c test/tox.${DISTRO}.ini
|
68
.gitignore
vendored
68
.gitignore
vendored
@@ -7,6 +7,70 @@ __pycache__
|
||||
.tox
|
||||
.eggs
|
||||
*.egg-info
|
||||
.idea/
|
||||
|
||||
|
||||
# Created by https://www.gitignore.io/api/jetbrains+iml
|
||||
|
||||
### JetBrains+iml ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# All idea files, with exceptions
|
||||
.idea
|
||||
!.idea/codeStyles/*
|
||||
!.idea/codeStyleSettings.xml
|
||||
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.xml
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# CMake
|
||||
cmake-build-debug/
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Ruby plugin and RubyMine
|
||||
/.rakeTasks
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
### JetBrains+iml Patch ###
|
||||
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
||||
|
||||
*.iml
|
||||
.vscode/
|
||||
.idea/misc.xml
|
||||
*.ipr
|
||||
|
||||
# End of https://www.gitignore.io/api/jetbrains+iml
|
||||
|
25
.idea/codeStyleSettings.xml
generated
Normal file
25
.idea/codeStyleSettings.xml
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectCodeStyleSettingsManager">
|
||||
<option name="PER_PROJECT_SETTINGS">
|
||||
<value>
|
||||
<option name="OTHER_INDENT_OPTIONS">
|
||||
<value>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="8" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
<option name="USE_TAB_CHARACTER" value="false" />
|
||||
<option name="SMART_TABS" value="false" />
|
||||
<option name="LABEL_INDENT_SIZE" value="0" />
|
||||
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
|
||||
<option name="USE_RELATIVE_INDENTS" value="false" />
|
||||
</value>
|
||||
</option>
|
||||
<MarkdownNavigatorCodeStyleSettings>
|
||||
<option name="RIGHT_MARGIN" value="72" />
|
||||
</MarkdownNavigatorCodeStyleSettings>
|
||||
</value>
|
||||
</option>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</component>
|
||||
</project>
|
7
.idea/codeStyles/Project.xml
generated
Normal file
7
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<MarkdownNavigatorCodeStyleSettings>
|
||||
<option name="RIGHT_MARGIN" value="72" />
|
||||
</MarkdownNavigatorCodeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
@@ -3,4 +3,3 @@ linters:
|
||||
shell: bash
|
||||
phpcs:
|
||||
flake8:
|
||||
max-line-length: 120
|
||||
|
5
.travis.yml
Normal file
5
.travis.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
import:
|
||||
- source: pi-hole/.github:/build-configs/core.yml@main
|
||||
if: branch = master
|
||||
- source: pi-hole/.github:/build-configs/core.yml@latest
|
||||
if: branch != master
|
@@ -2,6 +2,37 @@
|
||||
|
||||
Please read and understand the contribution guide before creating an issue or pull request.
|
||||
|
||||
The guide can be found here: [https://docs.pi-hole.net/guides/github/contributing/](https://docs.pi-hole.net/guides/github/contributing/)
|
||||
## Etiquette
|
||||
|
||||
- Our goal for Pi-hole is **stability before features**. This means we focus on squashing critical bugs before adding new features. Often, we can do both in tandem, but bugs will take priority over a new feature.
|
||||
- Pi-hole is open source and [powered by donations](https://pi-hole.net/donate/), and as such, we give our **free time** to build, maintain, and **provide user support** for this project. It would be extremely unfair for us to suffer abuse or anger for our hard work, so please take a moment to consider that.
|
||||
- Please be considerate towards the developers and other users when raising issues or presenting pull requests.
|
||||
- Respect our decision(s), and do not be upset or abusive if your submission is not used.
|
||||
|
||||
## Viability
|
||||
|
||||
When requesting or submitting new features, first consider whether it might be useful to others. Open source projects are used by many people, who may have entirely different needs to your own. Think about whether or not your feature is likely to be used by other users of the project.
|
||||
|
||||
## Procedure
|
||||
|
||||
**Before filing an issue:**
|
||||
|
||||
- Attempt to replicate and **document** the problem, to ensure that it wasn't a coincidental incident.
|
||||
- Check to make sure your feature suggestion isn't already present within the project.
|
||||
- Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
|
||||
- Check the pull requests tab to ensure that the feature isn't already in progress.
|
||||
|
||||
**Before submitting a pull request:**
|
||||
|
||||
- Check the codebase to ensure that your feature doesn't already exist.
|
||||
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
|
||||
- Read and understand the [DCO guidelines](https://github.com/pi-hole/pi-hole/wiki/Contributing-to-the-project) for the project.
|
||||
|
||||
## Technical Requirements
|
||||
|
||||
- Submit Pull Requests to the **development branch only**.
|
||||
- Before Submitting your Pull Request, merge `development` with your new branch and fix any conflicts. (Make sure you don't break anything in development!)
|
||||
- Please use the [Google Style Guide for Shell](https://google.github.io/styleguide/shell.xml) for your code submission styles.
|
||||
- Commit Unix line endings.
|
||||
- Please use the Pi-hole brand: **Pi-hole** (Take a special look at the capitalized 'P' and a low 'h' with a hyphen)
|
||||
- (Optional fun) keep to the theme of Star Trek/black holes/gravity.
|
||||
|
85
README.md
85
README.md
@@ -1,7 +1,5 @@
|
||||
<!-- markdownlint-configure-file { "MD004": { "style": "consistent" } } -->
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
#
|
||||
|
||||
<p align="center">
|
||||
<a href="https://pi-hole.net/">
|
||||
<img src="https://pi-hole.github.io/graphics/Vortex/Vortex_with_Wordmark.svg" width="150" height="260" alt="Pi-hole">
|
||||
@@ -11,9 +9,11 @@
|
||||
</p>
|
||||
<!-- markdownlint-enable MD033 -->
|
||||
|
||||
The Pi-hole® is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content without installing any client-side software.
|
||||
#
|
||||
|
||||
- **Easy-to-install**: our versatile installer walks you through the process and takes less than ten minutes
|
||||
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](https://www.youtube.com/watch?v=vKWjx1AQYgs)
|
||||
- **Resolute**: content is blocked in _non-browser locations_, such as ad-laden mobile apps and smart TVs
|
||||
- **Responsive**: seamlessly speeds up the feel of everyday browsing by caching DNS queries
|
||||
- **Lightweight**: runs smoothly with [minimal hardware and software requirements](https://docs.pi-hole.net/main/prerequisites/)
|
||||
@@ -22,10 +22,12 @@ The Pi-hole® is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) th
|
||||
- **Versatile**: can optionally function as a [DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026), ensuring *all* your devices are protected automatically
|
||||
- **Scalable**: [capable of handling hundreds of millions of queries](https://pi-hole.net/2017/05/24/how-much-traffic-can-pi-hole-handle/) when installed on server-grade hardware
|
||||
- **Modern**: blocks ads over both IPv4 and IPv6
|
||||
- **Free**: open source software that helps ensure _you_ are the sole person in control of your privacy
|
||||
- **Free**: open source software which helps ensure _you_ are the sole person in control of your privacy
|
||||
|
||||
-----
|
||||
|
||||
Master [](https://travis-ci.com/pi-hole/pi-hole) Development [](https://travis-ci.com/pi-hole/pi-hole)
|
||||
|
||||
## One-Step Automated Install
|
||||
|
||||
Those who want to get started quickly and conveniently may install Pi-hole using the following command:
|
||||
@@ -50,46 +52,42 @@ sudo bash basic-install.sh
|
||||
wget -O basic-install.sh https://install.pi-hole.net
|
||||
sudo bash basic-install.sh
|
||||
```
|
||||
### Method 3: Using Docker to deploy Pi-hole
|
||||
Please refer to the [Pi-hole docker repo](https://github.com/pi-hole/docker-pi-hole) to use the Official Docker Images.
|
||||
|
||||
## [Post-install: Make your network take advantage of Pi-hole](https://docs.pi-hole.net/main/post-install/)
|
||||
|
||||
Once the installer has been run, you will need to [configure your router to have **DHCP clients use Pi-hole as their DNS server**](https://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245) which ensures that all devices connecting to your network will have content blocked without any further intervention.
|
||||
|
||||
If your router does not support setting the DNS server, you can [use Pi-hole's built-in DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026); be sure to disable DHCP on your router first (if it has that feature available).
|
||||
If your router does not support setting the DNS server, you can [use Pi-hole's built-in DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026); just be sure to disable DHCP on your router first (if it has that feature available).
|
||||
|
||||
As a last resort, you can manually set each device to use Pi-hole as their DNS server.
|
||||
As a last resort, you can always manually set each device to use Pi-hole as their DNS server.
|
||||
|
||||
-----
|
||||
|
||||
## Pi-hole is free but powered by your support
|
||||
## Pi-hole is free, but powered by your support
|
||||
|
||||
There are many reoccurring costs involved with maintaining free, open source, and privacy-respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software and the importance of keeping it maintained.
|
||||
There are many reoccurring costs involved with maintaining free, open source, and privacy-respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software, as well as the importance of keeping it maintained.
|
||||
|
||||
Make no mistake: **your support is absolutely vital to help keep us innovating!**
|
||||
|
||||
### [Donations](https://pi-hole.net/donate)
|
||||
|
||||
Donating using our Sponsor Button is **extremely helpful** in offsetting a portion of our monthly expenses:
|
||||
Sending a donation using our Sponsor Button is **extremely helpful** in offsetting a portion of our monthly expenses:
|
||||
|
||||
### Alternative support
|
||||
|
||||
If you'd rather not donate (_which is okay!_), there are other ways you can help support us:
|
||||
|
||||
- [GitHub Sponsors](https://github.com/sponsors/pi-hole/)
|
||||
- [Patreon](https://patreon.com/pihole)
|
||||
- [Hetzner Cloud](https://hetzner.cloud/?ref=7aceisRX3AzA) _affiliate link_
|
||||
- [Patreon](https://patreon.com/pihole) _Become a patron for rewards_
|
||||
- [Digital Ocean](https://www.digitalocean.com/?refcode=344d234950e1) _affiliate link_
|
||||
- [Stickermule](https://www.stickermule.com/unlock?ref_id=9127301701&utm_medium=link&utm_source=invite) _earn a $10 credit after your first purchase_
|
||||
- [Amazon US](http://www.amazon.com/exec/obidos/redirect-home/pihole09-20) _affiliate link_
|
||||
- Spreading the word about our software and how you have benefited from it
|
||||
- [Amazon](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
|
||||
|
||||
### Contributing via GitHub
|
||||
|
||||
We welcome _everyone_ to contribute to issue reports, suggest new features, and create pull requests.
|
||||
|
||||
If you have something to add - anything from a typo through to a whole new feature, we're happy to check it out! Just make sure to fill out our template when submitting your request; the questions it asks will help the volunteers quickly understand what you're aiming to achieve.
|
||||
If you have something to add - anything from a typo through to a whole new feature, we're happy to check it out! Just make sure to fill out our template when submitting your request; the questions that it asks will help the volunteers quickly understand what you're aiming to achieve.
|
||||
|
||||
You'll find that the [install script](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) and the [debug script](https://github.com/pi-hole/pi-hole/blob/master/advanced/Scripts/piholeDebug.sh) have an abundance of comments, which will help you better understand how Pi-hole works. They're also a valuable resource to those who want to learn how to write scripts or code a program! We encourage anyone who likes to tinker to read through it and submit a pull request for us to review.
|
||||
|
||||
@@ -97,9 +95,7 @@ You'll find that the [install script](https://github.com/pi-hole/pi-hole/blob/ma
|
||||
|
||||
## Getting in touch with us
|
||||
|
||||
While we are primarily reachable on our [Discourse User Forum](https://discourse.pi-hole.net/), we can also be found on various social media outlets.
|
||||
|
||||
**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.
|
||||
While we are primarily reachable on our [Discourse User Forum](https://discourse.pi-hole.net/), we can also be found on a variety of social media outlets. **Please be sure to check the FAQ's** before starting a new discussion, as we do not have the spare time to reply to every request for assistance.
|
||||
|
||||
- [Frequently Asked Questions](https://discourse.pi-hole.net/c/faqs)
|
||||
- [Feature Requests](https://discourse.pi-hole.net/c/feature-requests?order=votes)
|
||||
@@ -110,30 +106,15 @@ While we are primarily reachable on our [Discourse User Forum](https://discourse
|
||||
|
||||
## Breakdown of Features
|
||||
|
||||
### [Faster-than-light Engine](https://github.com/pi-hole/ftl)
|
||||
|
||||
[FTLDNS](https://github.com/pi-hole/ftl) is a lightweight, purpose-built daemon used to provide statistics needed for the Web Interface, and its API can be easily integrated into your own projects. As the name implies, FTLDNS does this all *very quickly*!
|
||||
|
||||
Some of the statistics you can integrate include:
|
||||
|
||||
- Total number of domains being blocked
|
||||
- Total number of DNS queries today
|
||||
- Total number of ads blocked today
|
||||
- Percentage of ads blocked
|
||||
- Unique domains
|
||||
- Queries forwarded (to your chosen upstream DNS server)
|
||||
- Queries cached
|
||||
- Unique clients
|
||||
|
||||
Access the API via [`telnet`](https://github.com/pi-hole/FTL), the Web (`admin/api.php`) and Command Line (`pihole -c -j`). You can find out [more details over here](https://discourse.pi-hole.net/t/pi-hole-api/1863).
|
||||
|
||||
### The Command Line Interface
|
||||
|
||||
The [pihole](https://docs.pi-hole.net/core/pihole-command/) command has all the functionality necessary to fully administer the Pi-hole, without the need of the Web Interface. It's fast, user-friendly, and auditable by anyone with an understanding of `bash`.
|
||||
The [pihole](https://docs.pi-hole.net/core/pihole-command/) command has all the functionality necessary to be able to fully administer the Pi-hole, without the need of the Web Interface. It's fast, user-friendly, and auditable by anyone with an understanding of `bash`.
|
||||
|
||||

|
||||
|
||||
Some notable features include:
|
||||
|
||||
- [Whitelisting, Blacklisting, and Regex](https://docs.pi-hole.net/core/pihole-command/#whitelisting-blacklisting-and-regex)
|
||||
- [Whitelisting, Blacklisting and Regex](https://docs.pi-hole.net/core/pihole-command/#whitelisting-blacklisting-and-regex)
|
||||
- [Debugging utility](https://docs.pi-hole.net/core/pihole-command/#debugger)
|
||||
- [Viewing the live log file](https://docs.pi-hole.net/core/pihole-command/#tail)
|
||||
- [Updating Ad Lists](https://docs.pi-hole.net/core/pihole-command/#gravity)
|
||||
@@ -147,9 +128,11 @@ You can read our [Core Feature Breakdown](https://docs.pi-hole.net/core/pihole-c
|
||||
|
||||
This [optional dashboard](https://github.com/pi-hole/AdminLTE) allows you to view stats, change settings, and configure your Pi-hole. It's the power of the Command Line Interface, with none of the learning curve!
|
||||
|
||||

|
||||
|
||||
Some notable features include:
|
||||
|
||||
- Mobile-friendly interface
|
||||
- Mobile friendly interface
|
||||
- Password protection
|
||||
- Detailed graphs and doughnut charts
|
||||
- Top lists of domains and clients
|
||||
@@ -161,4 +144,22 @@ Some notable features include:
|
||||
There are several ways to [access the dashboard](https://discourse.pi-hole.net/t/how-do-i-access-pi-holes-dashboard-admin-interface/3168):
|
||||
|
||||
1. `http://pi.hole/admin/` (when using Pi-hole as your DNS server)
|
||||
2. `http://<IP_ADDRESS_OF_YOUR_PI_HOLE>/admin/`
|
||||
2. `http://<IP_ADDPRESS_OF_YOUR_PI_HOLE>/admin/`
|
||||
3. `http://pi.hole/` (when using Pi-hole as your DNS server)
|
||||
|
||||
## Faster-than-light Engine
|
||||
|
||||
FTLDNS is a lightweight, purpose-built daemon used to provide statistics needed for the Web Interface, and its API can be easily integrated into your own projects. As the name implies, FTLDNS does this all *very quickly*!
|
||||
|
||||
Some of the statistics you can integrate include:
|
||||
|
||||
- Total number of domains being blocked
|
||||
- Total number of DNS queries today
|
||||
- Total number of ads blocked today
|
||||
- Percentage of ads blocked
|
||||
- Unique domains
|
||||
- Queries forwarded (to your chosen upstream DNS server)
|
||||
- Queries cached
|
||||
- Unique clients
|
||||
|
||||
The API can be accessed via [`telnet`](https://github.com/pi-hole/FTL), the Web (`admin/api.php`) and Command Line (`pihole -c -j`). You can out find [more details over here](https://discourse.pi-hole.net/t/pi-hole-api/1863).
|
||||
|
@@ -34,9 +34,11 @@ server=@DNS2@
|
||||
|
||||
interface=@INT@
|
||||
|
||||
cache-size=@CACHE_SIZE@
|
||||
cache-size=10000
|
||||
|
||||
log-queries
|
||||
log-facility=/var/log/pihole.log
|
||||
|
||||
local-ttl=2
|
||||
|
||||
log-async
|
||||
|
@@ -1,42 +0,0 @@
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2021 Pi-hole, LLC (https://pi-hole.net)
|
||||
# Network-wide ad blocking via your own hardware.
|
||||
#
|
||||
# RFC 6761 config file for Pi-hole
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
###############################################################################
|
||||
# FILE AUTOMATICALLY POPULATED BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
|
||||
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
|
||||
# #
|
||||
# CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE #
|
||||
# WITHIN /etc/dnsmasq.d/yourname.conf #
|
||||
###############################################################################
|
||||
|
||||
# RFC 6761: Caching DNS servers SHOULD recognize
|
||||
# test, localhost, invalid
|
||||
# names as special and SHOULD NOT attempt to look up NS records for them, or
|
||||
# otherwise query authoritative DNS servers in an attempt to resolve these
|
||||
# names.
|
||||
server=/test/
|
||||
server=/localhost/
|
||||
server=/invalid/
|
||||
|
||||
# The same RFC requests something similar for
|
||||
# 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/
|
@@ -1,5 +1,5 @@
|
||||
# Determine if terminal is capable of showing colors
|
||||
if ([[ -t 1 ]] && [[ $(tput colors) -ge 8 ]]) || [[ "${WEBCALL}" ]]; then
|
||||
if [[ -t 1 ]] && [[ $(tput colors) -ge 8 ]]; then
|
||||
# Bold and underline may not show up on all clients
|
||||
# If something MUST be emphasized, use both
|
||||
COL_BOLD='[1m'
|
||||
|
@@ -13,7 +13,6 @@ LC_NUMERIC=C
|
||||
|
||||
# Retrieve stats from FTL engine
|
||||
pihole-FTL() {
|
||||
local ftl_port LINE
|
||||
ftl_port=$(cat /run/pihole-FTL.port 2> /dev/null)
|
||||
if [[ -n "$ftl_port" ]]; then
|
||||
# Open connection to FTL
|
||||
@@ -21,13 +20,12 @@ pihole-FTL() {
|
||||
|
||||
# Test if connection is open
|
||||
if { "true" >&3; } 2> /dev/null; then
|
||||
# Send command to FTL and ask to quit when finished
|
||||
echo -e ">$1 >quit" >&3
|
||||
# Send command to FTL
|
||||
echo -e ">$1" >&3
|
||||
|
||||
# Read input until we received an empty string and the connection is
|
||||
# closed
|
||||
# Read input
|
||||
read -r -t 1 LINE <&3
|
||||
until [[ -z "${LINE}" ]] && [[ ! -t 3 ]]; do
|
||||
until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do
|
||||
echo "$LINE" >&1
|
||||
read -r -t 1 LINE <&3
|
||||
done
|
||||
@@ -230,21 +228,15 @@ get_sys_stats() {
|
||||
mapfile -t ph_ver_raw < <(pihole -v -c 2> /dev/null | sed -n 's/^.* v/v/p')
|
||||
if [[ -n "${ph_ver_raw[0]}" ]]; then
|
||||
ph_core_ver="${ph_ver_raw[0]}"
|
||||
if [[ ${#ph_ver_raw[@]} -eq 2 ]]; then
|
||||
# AdminLTE not installed
|
||||
ph_lte_ver="(not installed)"
|
||||
ph_ftl_ver="${ph_ver_raw[1]}"
|
||||
else
|
||||
ph_lte_ver="${ph_ver_raw[1]}"
|
||||
ph_ftl_ver="${ph_ver_raw[2]}"
|
||||
fi
|
||||
ph_lte_ver="${ph_ver_raw[1]}"
|
||||
ph_ftl_ver="${ph_ver_raw[2]}"
|
||||
else
|
||||
ph_core_ver="-1"
|
||||
fi
|
||||
|
||||
sys_name=$(hostname)
|
||||
|
||||
[[ -n "$TEMPERATUREUNIT" ]] && temp_unit="${TEMPERATUREUNIT^^}" || temp_unit="C"
|
||||
[[ -n "$TEMPERATUREUNIT" ]] && temp_unit="$TEMPERATUREUNIT" || temp_unit="c"
|
||||
|
||||
# Get storage stats for partition mounted on /
|
||||
read -r -a disk_raw <<< "$(df -B1 / 2> /dev/null | awk 'END{ print $3,$2,$5 }')"
|
||||
@@ -329,8 +321,8 @@ get_sys_stats() {
|
||||
*) cpu_col="$COL_URG_RED";;
|
||||
esac
|
||||
|
||||
# $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED
|
||||
cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
|
||||
# $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED
|
||||
cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
|
||||
|
||||
elif [[ "$temp_unit" == "F" ]]; then
|
||||
cpu_temp=$(printf "%.0ff\\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")")
|
||||
@@ -357,7 +349,7 @@ get_sys_stats() {
|
||||
ram_used="${ram_raw[1]}"
|
||||
ram_total="${ram_raw[2]}"
|
||||
|
||||
if [[ "$(pihole status web 2> /dev/null)" -ge "1" ]]; then
|
||||
if [[ "$(pihole status web 2> /dev/null)" == "1" ]]; then
|
||||
ph_status="${COL_LIGHT_GREEN}Active"
|
||||
else
|
||||
ph_status="${COL_LIGHT_RED}Offline"
|
||||
@@ -445,7 +437,7 @@ get_strings() {
|
||||
lan_info="Gateway: $net_gateway"
|
||||
dhcp_info="$leased_str$ph_dhcp_num of $ph_dhcp_max"
|
||||
|
||||
ads_info="$total_str$ads_blocked_today of $dns_queries_today"
|
||||
ads_info="$total_str$ads_blocked_today of $dns_queries_today"
|
||||
dns_info="$dns_count DNS servers"
|
||||
|
||||
[[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}"
|
||||
@@ -488,7 +480,7 @@ chronoFunc() {
|
||||
${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC}
|
||||
${COL_DARK_GRAY}$scr_line_str${COL_NC}"
|
||||
else
|
||||
echo -e "[0;1;31;91m|¯[0;1;33;93m¯[0;1;32;92m¯[0;1;32;92m(¯[0;1;36;96m)[0;1;34;94m_[0;1;35;95m|[0;1;33;93m¯[0;1;31;91m|_ [0;1;32;92m__[0;1;36;96m_|[0;1;31;91m¯[0;1;34;94m|[0;1;35;95m__[0;1;31;91m_[0m$phc_ver_str\\n[0;1;33;93m| ¯[0;1;32;92m_[0;1;36;96m/¯[0;1;34;94m|[0;1;35;95m_[0;1;31;91m| [0;1;33;93m' [0;1;32;92m\\/ [0;1;36;96m_ [0;1;34;94m\\ [0;1;35;95m/ [0;1;31;91m-[0;1;33;93m_)[0m$lte_ver_str\\n[0;1;32;92m|_[0;1;36;96m| [0;1;34;94m|_[0;1;35;95m| [0;1;33;93m|_[0;1;32;92m||[0;1;36;96m_\\[0;1;34;94m__[0;1;35;95m_/[0;1;31;91m_\\[0;1;33;93m__[0;1;32;92m_|[0m$ftl_ver_str\\n ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
|
||||
echo -e "[0;1;31;91m|¯[0;1;33;93m¯[0;1;32;92m¯[0;1;32;92m(¯[0;1;36;96m)[0;1;34;94m_[0;1;35;95m|[0;1;33;93m¯[0;1;31;91m|_ [0;1;32;92m__[0;1;36;96m_|[0;1;31;91m¯[0;1;34;94m|[0;1;35;95m__[0;1;31;91m_[0m$phc_ver_str\\n[0;1;33;93m| ¯[0;1;32;92m_[0;1;36;96m/¯[0;1;34;94m|[0;1;35;95m_[0;1;31;91m| [0;1;33;93m' [0;1;32;92m\\/ [0;1;36;96m_ [0;1;34;94m\\ [0;1;35;95m/ [0;1;31;91m-[0;1;33;93m_)[0m$lte_ver_str\\n[0;1;32;92m|_[0;1;36;96m| [0;1;34;94m|_[0;1;35;95m| [0;1;33;93m|_[0;1;32;92m||[0;1;36;96m_\\[0;1;34;94m__[0;1;35;95m_/[0;1;31;91m_\\[0;1;33;93m__[0;1;32;92m_|[0m$ftl_ver_str\\n ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
|
||||
fi
|
||||
|
||||
printFunc " Hostname: " "$sys_name" "$host_info"
|
||||
@@ -498,6 +490,10 @@ chronoFunc() {
|
||||
printFunc " RAM usage: " "$ram_perc%" "$ram_info"
|
||||
printFunc " HDD usage: " "$disk_perc" "$disk_info"
|
||||
|
||||
if [[ "$scr_lines" -gt 17 ]] && [[ "$chrono_width" != "small" ]]; then
|
||||
printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}" "$lan_info"
|
||||
fi
|
||||
|
||||
if [[ "$DHCP_ACTIVE" == "true" ]]; then
|
||||
printFunc "DHCP usage: " "$ph_dhcp_percent%" "$dhcp_info"
|
||||
fi
|
||||
@@ -555,7 +551,7 @@ Calculates stats and displays to an LCD
|
||||
Options:
|
||||
-j, --json Output stats as JSON formatted string
|
||||
-r, --refresh Set update frequency (in seconds)
|
||||
-e, --exit Output stats and exit without refreshing
|
||||
-e, --exit Output stats and exit witout refreshing
|
||||
-h, --help Display this help text"
|
||||
fi
|
||||
|
||||
|
42
advanced/Scripts/database_migration/gravity-db.sh
Executable file → Normal file
42
advanced/Scripts/database_migration/gravity-db.sh
Executable file → Normal file
@@ -19,13 +19,13 @@ upgrade_gravityDB(){
|
||||
auditFile="${piholeDir}/auditlog.list"
|
||||
|
||||
# Get database version
|
||||
version="$(pihole-FTL sqlite3 "${database}" "SELECT \"value\" FROM \"info\" WHERE \"property\" = 'version';")"
|
||||
version="$(sqlite3 "${database}" "SELECT \"value\" FROM \"info\" WHERE \"property\" = 'version';")"
|
||||
|
||||
if [[ "$version" == "1" ]]; then
|
||||
# This migration script upgrades the gravity.db file by
|
||||
# adding the domain_audit table
|
||||
echo -e " ${INFO} Upgrading gravity database from version 1 to 2"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/1_to_2.sql"
|
||||
sqlite3 "${database}" < "${scriptPath}/1_to_2.sql"
|
||||
version=2
|
||||
|
||||
# Store audit domains in database table
|
||||
@@ -40,28 +40,28 @@ upgrade_gravityDB(){
|
||||
# renaming the regex table to regex_blacklist, and
|
||||
# creating a new regex_whitelist table + corresponding linking table and views
|
||||
echo -e " ${INFO} Upgrading gravity database from version 2 to 3"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/2_to_3.sql"
|
||||
sqlite3 "${database}" < "${scriptPath}/2_to_3.sql"
|
||||
version=3
|
||||
fi
|
||||
if [[ "$version" == "3" ]]; then
|
||||
# This migration script unifies the formally separated domain
|
||||
# lists into a single table with a UNIQUE domain constraint
|
||||
echo -e " ${INFO} Upgrading gravity database from version 3 to 4"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/3_to_4.sql"
|
||||
sqlite3 "${database}" < "${scriptPath}/3_to_4.sql"
|
||||
version=4
|
||||
fi
|
||||
if [[ "$version" == "4" ]]; then
|
||||
# This migration script upgrades the gravity and list views
|
||||
# implementing necessary changes for per-client blocking
|
||||
echo -e " ${INFO} Upgrading gravity database from version 4 to 5"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/4_to_5.sql"
|
||||
sqlite3 "${database}" < "${scriptPath}/4_to_5.sql"
|
||||
version=5
|
||||
fi
|
||||
if [[ "$version" == "5" ]]; then
|
||||
# This migration script upgrades the adlist view
|
||||
# to return an ID used in gravity.sh
|
||||
echo -e " ${INFO} Upgrading gravity database from version 5 to 6"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/5_to_6.sql"
|
||||
sqlite3 "${database}" < "${scriptPath}/5_to_6.sql"
|
||||
version=6
|
||||
fi
|
||||
if [[ "$version" == "6" ]]; then
|
||||
@@ -69,7 +69,7 @@ upgrade_gravityDB(){
|
||||
# which is automatically associated to all clients not
|
||||
# having their own group assignments
|
||||
echo -e " ${INFO} Upgrading gravity database from version 6 to 7"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/6_to_7.sql"
|
||||
sqlite3 "${database}" < "${scriptPath}/6_to_7.sql"
|
||||
version=7
|
||||
fi
|
||||
if [[ "$version" == "7" ]]; then
|
||||
@@ -77,21 +77,21 @@ upgrade_gravityDB(){
|
||||
# to ensure uniqueness on the group name
|
||||
# We also add date_added and date_modified columns
|
||||
echo -e " ${INFO} Upgrading gravity database from version 7 to 8"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/7_to_8.sql"
|
||||
sqlite3 "${database}" < "${scriptPath}/7_to_8.sql"
|
||||
version=8
|
||||
fi
|
||||
if [[ "$version" == "8" ]]; then
|
||||
# This migration fixes some issues that were introduced
|
||||
# in the previous migration script.
|
||||
echo -e " ${INFO} Upgrading gravity database from version 8 to 9"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/8_to_9.sql"
|
||||
sqlite3 "${database}" < "${scriptPath}/8_to_9.sql"
|
||||
version=9
|
||||
fi
|
||||
if [[ "$version" == "9" ]]; then
|
||||
# This migration drops unused tables and creates triggers to remove
|
||||
# obsolete groups assignments when the linked items are deleted
|
||||
echo -e " ${INFO} Upgrading gravity database from version 9 to 10"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/9_to_10.sql"
|
||||
sqlite3 "${database}" < "${scriptPath}/9_to_10.sql"
|
||||
version=10
|
||||
fi
|
||||
if [[ "$version" == "10" ]]; then
|
||||
@@ -101,31 +101,13 @@ upgrade_gravityDB(){
|
||||
# to keep the copying process generic (needs the same columns in both the
|
||||
# source and the destination databases).
|
||||
echo -e " ${INFO} Upgrading gravity database from version 10 to 11"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/10_to_11.sql"
|
||||
sqlite3 "${database}" < "${scriptPath}/10_to_11.sql"
|
||||
version=11
|
||||
fi
|
||||
if [[ "$version" == "11" ]]; then
|
||||
# Rename group 0 from "Unassociated" to "Default"
|
||||
echo -e " ${INFO} Upgrading gravity database from version 11 to 12"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/11_to_12.sql"
|
||||
sqlite3 "${database}" < "${scriptPath}/11_to_12.sql"
|
||||
version=12
|
||||
fi
|
||||
if [[ "$version" == "12" ]]; then
|
||||
# Add column date_updated to adlist table
|
||||
echo -e " ${INFO} Upgrading gravity database from version 12 to 13"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/12_to_13.sql"
|
||||
version=13
|
||||
fi
|
||||
if [[ "$version" == "13" ]]; then
|
||||
# Add columns number and status to adlist table
|
||||
echo -e " ${INFO} Upgrading gravity database from version 13 to 14"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/13_to_14.sql"
|
||||
version=14
|
||||
fi
|
||||
if [[ "$version" == "14" ]]; then
|
||||
# Changes the vw_adlist created in 5_to_6
|
||||
echo -e " ${INFO} Upgrading gravity database from version 14 to 15"
|
||||
pihole-FTL sqlite3 "${database}" < "${scriptPath}/14_to_15.sql"
|
||||
version=15
|
||||
fi
|
||||
}
|
||||
|
@@ -1,18 +0,0 @@
|
||||
.timeout 30000
|
||||
|
||||
PRAGMA FOREIGN_KEYS=OFF;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
ALTER TABLE adlist ADD COLUMN date_updated INTEGER;
|
||||
|
||||
DROP TRIGGER tr_adlist_update;
|
||||
|
||||
CREATE TRIGGER tr_adlist_update AFTER UPDATE OF address,enabled,comment ON adlist
|
||||
BEGIN
|
||||
UPDATE adlist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
||||
END;
|
||||
|
||||
UPDATE info SET value = 13 WHERE property = 'version';
|
||||
|
||||
COMMIT;
|
@@ -1,13 +0,0 @@
|
||||
.timeout 30000
|
||||
|
||||
PRAGMA FOREIGN_KEYS=OFF;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
ALTER TABLE adlist ADD COLUMN number INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE adlist ADD COLUMN invalid_domains INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE adlist ADD COLUMN status INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
UPDATE info SET value = 14 WHERE property = 'version';
|
||||
|
||||
COMMIT;
|
@@ -1,15 +0,0 @@
|
||||
.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;
|
@@ -1,6 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC1090
|
||||
|
||||
# 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.
|
||||
@@ -11,19 +9,11 @@
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
# Globals
|
||||
piholeDir="/etc/pihole"
|
||||
GRAVITYDB="${piholeDir}/gravity.db"
|
||||
# Source pihole-FTL from install script
|
||||
pihole_FTL="${piholeDir}/pihole-FTL.conf"
|
||||
if [[ -f "${pihole_FTL}" ]]; then
|
||||
source "${pihole_FTL}"
|
||||
fi
|
||||
basename=pihole
|
||||
piholeDir=/etc/"${basename}"
|
||||
gravityDBfile="${piholeDir}/gravity.db"
|
||||
|
||||
# Set this only after sourcing pihole-FTL.conf as the gravity database path may
|
||||
# have changed
|
||||
gravityDBfile="${GRAVITYDB}"
|
||||
|
||||
noReloadRequested=false
|
||||
reload=false
|
||||
addmode=true
|
||||
verbose=true
|
||||
wildcard=false
|
||||
@@ -35,7 +25,6 @@ typeId=""
|
||||
comment=""
|
||||
declare -i domaincount
|
||||
domaincount=0
|
||||
reload=false
|
||||
|
||||
colfile="/opt/pihole/COL_TABLE"
|
||||
source ${colfile}
|
||||
@@ -91,8 +80,7 @@ Options:
|
||||
-q, --quiet Make output less verbose
|
||||
-h, --help Show this help dialog
|
||||
-l, --list Display all your ${listname}listed domains
|
||||
--nuke Removes all entries in a list
|
||||
--comment \"text\" Add a comment to the domain. If adding multiple domains the same comment will be used for all"
|
||||
--nuke Removes all entries in a list"
|
||||
|
||||
exit 0
|
||||
}
|
||||
@@ -124,7 +112,7 @@ ProcessDomainList() {
|
||||
for dom in "${domList[@]}"; do
|
||||
# Format domain into regex filter if requested
|
||||
if [[ "${wildcard}" == true ]]; then
|
||||
dom="(\\.|^)${dom//\./\\.}$"
|
||||
dom="(^|\\.)${dom//\./\\.}$"
|
||||
fi
|
||||
|
||||
# Logic: If addmode then add to desired list and remove from the other;
|
||||
@@ -134,7 +122,7 @@ ProcessDomainList() {
|
||||
else
|
||||
RemoveDomain "${dom}"
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
AddDomain() {
|
||||
@@ -142,23 +130,23 @@ AddDomain() {
|
||||
domain="$1"
|
||||
|
||||
# Is the domain in the list we want to add it to?
|
||||
num="$(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT COUNT(*) FROM domainlist WHERE domain = '${domain}';")"
|
||||
num="$(sqlite3 "${gravityDBfile}" "SELECT COUNT(*) FROM domainlist WHERE domain = '${domain}';")"
|
||||
requestedListname="$(GetListnameFromTypeId "${typeId}")"
|
||||
|
||||
if [[ "${num}" -ne 0 ]]; then
|
||||
existingTypeId="$(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT type FROM domainlist WHERE domain = '${domain}';")"
|
||||
if [[ "${existingTypeId}" == "${typeId}" ]]; then
|
||||
if [[ "${verbose}" == true ]]; then
|
||||
echo -e " ${INFO} ${1} already exists in ${requestedListname}, no need to add!"
|
||||
fi
|
||||
else
|
||||
existingListname="$(GetListnameFromTypeId "${existingTypeId}")"
|
||||
pihole-FTL 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
|
||||
existingTypeId="$(sqlite3 "${gravityDBfile}" "SELECT type FROM domainlist WHERE domain = '${domain}';")"
|
||||
if [[ "${existingTypeId}" == "${typeId}" ]]; then
|
||||
if [[ "${verbose}" == true ]]; then
|
||||
echo -e " ${INFO} ${1} already exists in ${requestedListname}, no need to add!"
|
||||
fi
|
||||
return
|
||||
else
|
||||
existingListname="$(GetListnameFromTypeId "${existingTypeId}")"
|
||||
sqlite3 "${gravityDBfile}" "UPDATE domainlist SET type = ${typeId} WHERE domain='${domain}';"
|
||||
if [[ "${verbose}" == true ]]; then
|
||||
echo -e " ${INFO} ${1} already exists in ${existingListname}, it has been moved to ${requestedListname}!"
|
||||
fi
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
# Domain not found in the table, add it!
|
||||
@@ -169,10 +157,10 @@ AddDomain() {
|
||||
# Insert only the domain here. The enabled and date_added fields will be filled
|
||||
# with their default values (enabled = true, date_added = current timestamp)
|
||||
if [[ -z "${comment}" ]]; then
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "INSERT INTO domainlist (domain,type) VALUES ('${domain}',${typeId});"
|
||||
sqlite3 "${gravityDBfile}" "INSERT INTO domainlist (domain,type) VALUES ('${domain}',${typeId});"
|
||||
else
|
||||
# also add comment when variable has been set through the "--comment" option
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "INSERT INTO domainlist (domain,type,comment) VALUES ('${domain}',${typeId},'${comment}');"
|
||||
sqlite3 "${gravityDBfile}" "INSERT INTO domainlist (domain,type,comment) VALUES ('${domain}',${typeId},'${comment}');"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -181,15 +169,15 @@ RemoveDomain() {
|
||||
domain="$1"
|
||||
|
||||
# Is the domain in the list we want to remove it from?
|
||||
num="$(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT COUNT(*) FROM domainlist WHERE domain = '${domain}' AND type = ${typeId};")"
|
||||
num="$(sqlite3 "${gravityDBfile}" "SELECT COUNT(*) FROM domainlist WHERE domain = '${domain}' AND type = ${typeId};")"
|
||||
|
||||
requestedListname="$(GetListnameFromTypeId "${typeId}")"
|
||||
|
||||
if [[ "${num}" -eq 0 ]]; then
|
||||
if [[ "${verbose}" == true ]]; then
|
||||
echo -e " ${INFO} ${domain} does not exist in ${requestedListname}, no need to remove!"
|
||||
fi
|
||||
return
|
||||
if [[ "${verbose}" == true ]]; then
|
||||
echo -e " ${INFO} ${domain} does not exist in ${requestedListname}, no need to remove!"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
# Domain found in the table, remove it!
|
||||
@@ -198,14 +186,14 @@ RemoveDomain() {
|
||||
fi
|
||||
reload=true
|
||||
# Remove it from the current list
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "DELETE FROM domainlist WHERE domain = '${domain}' AND type = ${typeId};"
|
||||
sqlite3 "${gravityDBfile}" "DELETE FROM domainlist WHERE domain = '${domain}' AND type = ${typeId};"
|
||||
}
|
||||
|
||||
Displaylist() {
|
||||
local count num_pipes domain enabled status nicedate requestedListname
|
||||
|
||||
requestedListname="$(GetListnameFromTypeId "${typeId}")"
|
||||
data="$(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT domain,enabled,date_modified FROM domainlist WHERE type = ${typeId};" 2> /dev/null)"
|
||||
data="$(sqlite3 "${gravityDBfile}" "SELECT domain,enabled,date_modified FROM domainlist WHERE type = ${typeId};" 2> /dev/null)"
|
||||
|
||||
if [[ -z $data ]]; then
|
||||
echo -e "Not showing empty list"
|
||||
@@ -243,22 +231,14 @@ Displaylist() {
|
||||
}
|
||||
|
||||
NukeList() {
|
||||
count=$(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT COUNT(1) FROM domainlist WHERE type = ${typeId};")
|
||||
listname="$(GetListnameFromTypeId "${typeId}")"
|
||||
if [ "$count" -gt 0 ];then
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "DELETE FROM domainlist WHERE type = ${typeId};"
|
||||
echo " ${TICK} Removed ${count} domain(s) from the ${listname}"
|
||||
else
|
||||
echo " ${INFO} ${listname} already empty. Nothing to do!"
|
||||
fi
|
||||
exit 0;
|
||||
sqlite3 "${gravityDBfile}" "DELETE FROM domainlist WHERE type = ${typeId};"
|
||||
}
|
||||
|
||||
GetComment() {
|
||||
comment="$1"
|
||||
if [[ "${comment}" =~ [^a-zA-Z0-9_\#:/\.,\ -] ]]; then
|
||||
echo " ${CROSS} Found invalid characters in domain comment!"
|
||||
exit
|
||||
echo " ${CROSS} Found invalid characters in domain comment!"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -270,7 +250,7 @@ while (( "$#" )); do
|
||||
"--white-wild" | "white-wild" ) typeId=2; wildcard=true;;
|
||||
"--wild" | "wildcard" ) typeId=3; wildcard=true;;
|
||||
"--regex" | "regex" ) typeId=3;;
|
||||
"-nr"| "--noreload" ) noReloadRequested=true;;
|
||||
"-nr"| "--noreload" ) reload=false;;
|
||||
"-d" | "--delmode" ) addmode=false;;
|
||||
"-q" | "--quiet" ) verbose=false;;
|
||||
"-h" | "--help" ) helpFunc;;
|
||||
@@ -293,9 +273,9 @@ ProcessDomainList
|
||||
|
||||
# Used on web interface
|
||||
if $web; then
|
||||
echo "DONE"
|
||||
echo "DONE"
|
||||
fi
|
||||
|
||||
if [[ ${reload} == true && ${noReloadRequested} == false ]]; then
|
||||
if [[ "${reload}" != false ]]; then
|
||||
pihole restartdns reload-lists
|
||||
fi
|
||||
|
@@ -38,8 +38,8 @@ flushARP(){
|
||||
|
||||
# Truncate network_addresses table in pihole-FTL.db
|
||||
# This needs to be done before we can truncate the network table due to
|
||||
# foreign key constraints
|
||||
if ! output=$(pihole-FTL sqlite3 "${DBFILE}" "DELETE FROM network_addresses" 2>&1); then
|
||||
# foreign key contraints
|
||||
if ! output=$(sqlite3 "${DBFILE}" "DELETE FROM network_addresses" 2>&1); then
|
||||
echo -e "${OVER} ${CROSS} Failed to truncate network_addresses table"
|
||||
echo " Database location: ${DBFILE}"
|
||||
echo " Output: ${output}"
|
||||
@@ -47,7 +47,7 @@ flushARP(){
|
||||
fi
|
||||
|
||||
# Truncate network table in pihole-FTL.db
|
||||
if ! output=$(pihole-FTL sqlite3 "${DBFILE}" "DELETE FROM network" 2>&1); then
|
||||
if ! output=$(sqlite3 "${DBFILE}" "DELETE FROM network" 2>&1); then
|
||||
echo -e "${OVER} ${CROSS} Failed to truncate network table"
|
||||
echo " Database location: ${DBFILE}"
|
||||
echo " Output: ${output}"
|
||||
|
3
advanced/Scripts/piholeCheckout.sh
Executable file → Normal file
3
advanced/Scripts/piholeCheckout.sh
Executable file → Normal file
@@ -166,15 +166,12 @@ checkout() {
|
||||
checkout_pull_branch "${webInterfaceDir}" "${2}"
|
||||
elif [[ "${1}" == "ftl" ]] ; then
|
||||
local path
|
||||
local oldbranch
|
||||
path="${2}/${binary}"
|
||||
oldbranch="$(pihole-FTL -b)"
|
||||
|
||||
if check_download_exists "$path"; then
|
||||
echo " ${TICK} Branch ${2} exists"
|
||||
echo "${2}" > /etc/pihole/ftlbranch
|
||||
chmod 644 /etc/pihole/ftlbranch
|
||||
echo -e " ${INFO} Switching to branch: \"${2}\" from \"${oldbranch}\""
|
||||
FTLinstall "${binary}"
|
||||
restart_service pihole-FTL
|
||||
enable_service pihole-FTL
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -11,11 +11,6 @@
|
||||
colfile="/opt/pihole/COL_TABLE"
|
||||
source ${colfile}
|
||||
|
||||
# In case we're running at the same time as a system logrotate, use a
|
||||
# separate logrotate state file to prevent stepping on each other's
|
||||
# toes.
|
||||
STATEFILE="/var/lib/logrotate/pihole"
|
||||
|
||||
# Determine database location
|
||||
# Obtain DBFILE=... setting from pihole-FTL.db
|
||||
# Constructed to return nothing when
|
||||
@@ -37,7 +32,7 @@ if [[ "$@" == *"once"* ]]; then
|
||||
# Nightly logrotation
|
||||
if command -v /usr/sbin/logrotate >/dev/null; then
|
||||
# Logrotate once
|
||||
/usr/sbin/logrotate --force --state "${STATEFILE}" /etc/pihole/logrotate
|
||||
/usr/sbin/logrotate --force /etc/pihole/logrotate
|
||||
else
|
||||
# Copy pihole.log over to pihole.log.1
|
||||
# and empty out pihole.log
|
||||
@@ -52,8 +47,8 @@ else
|
||||
# Manual flushing
|
||||
if command -v /usr/sbin/logrotate >/dev/null; then
|
||||
# Logrotate twice to move all data out of sight of FTL
|
||||
/usr/sbin/logrotate --force --state "${STATEFILE}" /etc/pihole/logrotate; sleep 3
|
||||
/usr/sbin/logrotate --force --state "${STATEFILE}" /etc/pihole/logrotate
|
||||
/usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3
|
||||
/usr/sbin/logrotate --force /etc/pihole/logrotate
|
||||
else
|
||||
# Flush both pihole.log and pihole.log.1 (if existing)
|
||||
echo " " > /var/log/pihole.log
|
||||
@@ -63,7 +58,7 @@ else
|
||||
fi
|
||||
fi
|
||||
# Delete most recent 24 hours from FTL's database, leave even older data intact (don't wipe out all history)
|
||||
deleted=$(pihole-FTL sqlite3 "${DBFILE}" "DELETE FROM query_storage WHERE timestamp >= strftime('%s','now')-86400; select changes() from query_storage limit 1")
|
||||
deleted=$(sqlite3 "${DBFILE}" "DELETE FROM queries WHERE timestamp >= strftime('%s','now')-86400; select changes() from queries limit 1")
|
||||
|
||||
# Restart pihole-FTL to force reloading history
|
||||
sudo pihole restartdns
|
||||
|
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC1090
|
||||
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2018 Pi-hole, LLC (https://pi-hole.net)
|
||||
# Network-wide ad blocking via your own hardware.
|
||||
@@ -12,21 +11,12 @@
|
||||
|
||||
# Globals
|
||||
piholeDir="/etc/pihole"
|
||||
GRAVITYDB="${piholeDir}/gravity.db"
|
||||
gravityDBfile="${piholeDir}/gravity.db"
|
||||
options="$*"
|
||||
all=""
|
||||
exact=""
|
||||
blockpage=""
|
||||
matchType="match"
|
||||
# Source pihole-FTL from install script
|
||||
pihole_FTL="${piholeDir}/pihole-FTL.conf"
|
||||
if [[ -f "${pihole_FTL}" ]]; then
|
||||
source "${pihole_FTL}"
|
||||
fi
|
||||
|
||||
# Set this only after sourcing pihole-FTL.conf as the gravity database path may
|
||||
# have changed
|
||||
gravityDBfile="${GRAVITYDB}"
|
||||
|
||||
colfile="/opt/pihole/COL_TABLE"
|
||||
source "${colfile}"
|
||||
@@ -48,7 +38,7 @@ scanList(){
|
||||
# Iterate through each regexp and check whether it matches the domainQuery
|
||||
# If it does, print the matching regexp and continue looping
|
||||
# Input 1 - regexps | Input 2 - domainQuery
|
||||
"regex" )
|
||||
"regex" )
|
||||
for list in ${lists}; do
|
||||
if [[ "${domain}" =~ ${list} ]]; then
|
||||
printf "%b\n" "${list}";
|
||||
@@ -64,8 +54,8 @@ Example: 'pihole -q -exact domain.com'
|
||||
Query the adlists for a specified domain
|
||||
|
||||
Options:
|
||||
-exact Search the adlists for exact domain matches
|
||||
-all Return all query matches within the adlists
|
||||
-exact Search the block lists for exact domain matches
|
||||
-all Return all query matches within a block list
|
||||
-h, --help Show this help dialog"
|
||||
exit 0
|
||||
fi
|
||||
@@ -109,27 +99,27 @@ scanDatabaseTable() {
|
||||
# behavior. The "ESCAPE '\'" clause specifies that an underscore preceded by an '\' should be matched
|
||||
# as a literal underscore character. We pretreat the $domain variable accordingly to escape underscores.
|
||||
if [[ "${table}" == "gravity" ]]; then
|
||||
case "${exact}" in
|
||||
"exact" ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain = '${domain}'";;
|
||||
* ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
|
||||
esac
|
||||
case "${exact}" in
|
||||
"exact" ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain = '${domain}'";;
|
||||
* ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
|
||||
esac
|
||||
else
|
||||
case "${exact}" in
|
||||
"exact" ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain = '${domain}'";;
|
||||
* ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
|
||||
esac
|
||||
case "${exact}" in
|
||||
"exact" ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain = '${domain}'";;
|
||||
* ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Send prepared query to gravity database
|
||||
result="$(pihole-FTL sqlite3 "${gravityDBfile}" "${querystr}")" 2> /dev/null
|
||||
result="$(sqlite3 "${gravityDBfile}" "${querystr}")" 2> /dev/null
|
||||
if [[ -z "${result}" ]]; then
|
||||
# Return early when there are no matches in this table
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "${table}" == "gravity" ]]; then
|
||||
echo "${result}"
|
||||
return
|
||||
echo "${result}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Mark domain as having been white-/blacklist matched (global variable)
|
||||
@@ -164,7 +154,7 @@ scanRegexDatabaseTable() {
|
||||
type="${3:-}"
|
||||
|
||||
# Query all regex from the corresponding database tables
|
||||
mapfile -t regexList < <(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT domain FROM domainlist WHERE type = ${type}" 2> /dev/null)
|
||||
mapfile -t regexList < <(sqlite3 "${gravityDBfile}" "SELECT domain FROM domainlist WHERE type = ${type}" 2> /dev/null)
|
||||
|
||||
# If we have regexps to process
|
||||
if [[ "${#regexList[@]}" -ne 0 ]]; then
|
||||
@@ -210,7 +200,7 @@ mapfile -t results <<< "$(scanDatabaseTable "${domainQuery}" "gravity")"
|
||||
|
||||
# Handle notices
|
||||
if [[ -z "${wbMatch:-}" ]] && [[ -z "${wcMatch:-}" ]] && [[ -z "${results[*]}" ]]; then
|
||||
echo -e " ${INFO} No ${exact/t/t }results found for ${COL_BOLD}${domainQuery}${COL_NC} within the adlists"
|
||||
echo -e " ${INFO} No ${exact/t/t }results found for ${COL_BOLD}${domainQuery}${COL_NC} within the block lists"
|
||||
exit 0
|
||||
elif [[ -z "${results[*]}" ]]; then
|
||||
# Result found in WL/BL/Wildcards
|
||||
@@ -233,15 +223,15 @@ for result in "${results[@]}"; do
|
||||
adlistAddress="${extra/|*/}"
|
||||
extra="${extra#*|}"
|
||||
if [[ "${extra}" == "0" ]]; then
|
||||
extra=" (disabled)"
|
||||
extra="(disabled)"
|
||||
else
|
||||
extra=""
|
||||
extra=""
|
||||
fi
|
||||
|
||||
if [[ -n "${blockpage}" ]]; then
|
||||
echo "0 ${adlistAddress}"
|
||||
elif [[ -n "${exact}" ]]; then
|
||||
echo " - ${adlistAddress}${extra}"
|
||||
echo " - ${adlistAddress} ${extra}"
|
||||
else
|
||||
if [[ ! "${adlistAddress}" == "${adlistAddress_prev:-}" ]]; then
|
||||
count=""
|
||||
@@ -256,7 +246,7 @@ for result in "${results[@]}"; do
|
||||
[[ "${count}" -gt "${max_count}" ]] && continue
|
||||
echo " ${COL_GRAY}Over ${count} results found, skipping rest of file${COL_NC}"
|
||||
else
|
||||
echo " ${match}${extra}"
|
||||
echo " ${match} ${extra}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
@@ -35,7 +35,6 @@ source "/opt/pihole/COL_TABLE"
|
||||
|
||||
GitCheckUpdateAvail() {
|
||||
local directory
|
||||
local curBranch
|
||||
directory="${1}"
|
||||
curdir=$PWD
|
||||
cd "${directory}" || return
|
||||
@@ -43,29 +42,18 @@ GitCheckUpdateAvail() {
|
||||
# Fetch latest changes in this repo
|
||||
git fetch --quiet origin
|
||||
|
||||
# Check current branch. If it is master, then check for the latest available tag instead of latest commit.
|
||||
curBranch=$(git rev-parse --abbrev-ref HEAD)
|
||||
if [[ "${curBranch}" == "master" ]]; then
|
||||
# get the latest local tag
|
||||
LOCAL=$(git describe --abbrev=0 --tags master)
|
||||
# get the latest tag from remote
|
||||
REMOTE=$(git describe --abbrev=0 --tags origin/master)
|
||||
|
||||
else
|
||||
# @ alone is a shortcut for HEAD. Older versions of git
|
||||
# need @{0}
|
||||
LOCAL="$(git rev-parse "@{0}")"
|
||||
|
||||
# The suffix @{upstream} to a branchname
|
||||
# (short form <branchname>@{u}) refers
|
||||
# to the branch that the branch specified
|
||||
# by branchname is set to build on top of#
|
||||
# (configured with branch.<name>.remote and
|
||||
# branch.<name>.merge). A missing branchname
|
||||
# defaults to the current one.
|
||||
REMOTE="$(git rev-parse "@{upstream}")"
|
||||
fi
|
||||
# @ alone is a shortcut for HEAD. Older versions of git
|
||||
# need @{0}
|
||||
LOCAL="$(git rev-parse "@{0}")"
|
||||
|
||||
# The suffix @{upstream} to a branchname
|
||||
# (short form <branchname>@{u}) refers
|
||||
# to the branch that the branch specified
|
||||
# by branchname is set to build on top of#
|
||||
# (configured with branch.<name>.remote and
|
||||
# branch.<name>.merge). A missing branchname
|
||||
# defaults to the current one.
|
||||
REMOTE="$(git rev-parse "@{upstream}")"
|
||||
|
||||
if [[ "${#LOCAL}" == 0 ]]; then
|
||||
echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support"
|
||||
@@ -107,10 +95,6 @@ main() {
|
||||
# shellcheck disable=1090,2154
|
||||
source "${setupVars}"
|
||||
|
||||
# Install packages used by this installation script (necessary if users have removed e.g. git from their systems)
|
||||
package_manager_detect
|
||||
install_dependent_packages "${INSTALLER_DEPS[@]}"
|
||||
|
||||
# This is unlikely
|
||||
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||
echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!"
|
||||
@@ -212,7 +196,7 @@ main() {
|
||||
|
||||
if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then
|
||||
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
|
||||
echo -e "${basicError}" && exit 1
|
||||
echo -e "${basicError}" && exit 1
|
||||
fi
|
||||
|
||||
if [[ "${FTL_update}" == true || "${core_update}" == true || "${web_update}" == true ]]; then
|
||||
|
@@ -1,92 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC3043 #https://github.com/koalaman/shellcheck/wiki/SC3043#exceptions
|
||||
|
||||
# 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.
|
||||
#
|
||||
# Script to hold utility functions for use in other scripts
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
# Basic Housekeeping rules
|
||||
# - Functions must be self contained
|
||||
# - Functions must be added in alphabetical order
|
||||
# - Functions must be documented
|
||||
# - New functions must have a test added for them in test/test_any_utils.py
|
||||
|
||||
#######################
|
||||
# Takes either
|
||||
# - Three arguments: file, key, and value.
|
||||
# - Two arguments: file, and key.
|
||||
#
|
||||
# Checks the target file for the existence of the key
|
||||
# - If it exists, it changes the value
|
||||
# - If it does not exist, it adds the value
|
||||
#
|
||||
# Example usage:
|
||||
# addOrEditKeyValuePair "/etc/pihole/setupVars.conf" "BLOCKING_ENABLED" "true"
|
||||
#######################
|
||||
addOrEditKeyValPair() {
|
||||
local file="${1}"
|
||||
local key="${2}"
|
||||
local value="${3}"
|
||||
|
||||
if [ "${value}" != "" ]; then
|
||||
# value has a value, so it is a key-value pair
|
||||
if grep -q "^${key}=" "${file}"; then
|
||||
# Key already exists in file, modify the value
|
||||
sed -i "/^${key}=/c\\${key}=${value}" "${file}"
|
||||
else
|
||||
# Key does not already exist, add it and it's value
|
||||
echo "${key}=${value}" >> "${file}"
|
||||
fi
|
||||
else
|
||||
# value has no value, so it is just a key. Add it if it does not already exist
|
||||
if ! grep -q "^${key}" "${file}"; then
|
||||
# Key does not exist, add it.
|
||||
echo "${key}" >> "${file}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#######################
|
||||
# Takes two arguments file, and key.
|
||||
# Deletes a key from target file
|
||||
#
|
||||
# Example usage:
|
||||
# removeKey "/etc/pihole/setupVars.conf" "PIHOLE_DNS_1"
|
||||
#######################
|
||||
removeKey() {
|
||||
local file="${1}"
|
||||
local key="${2}"
|
||||
sed -i "/^${key}/d" "${file}"
|
||||
}
|
||||
|
||||
#######################
|
||||
# returns FTL's current telnet API port
|
||||
#######################
|
||||
getFTLAPIPort(){
|
||||
local FTLCONFFILE="/etc/pihole/pihole-FTL.conf"
|
||||
local DEFAULT_PORT_FILE="/run/pihole-FTL.port"
|
||||
local DEFAULT_FTL_PORT=4711
|
||||
local PORTFILE
|
||||
local ftl_api_port
|
||||
|
||||
if [ -f "$FTLCONFFILE" ]; then
|
||||
# if PORTFILE is not set in pihole-FTL.conf, use the default path
|
||||
PORTFILE="$( (grep "^PORTFILE=" $FTLCONFFILE || echo "$DEFAULT_PORT_FILE") | cut -d"=" -f2-)"
|
||||
fi
|
||||
|
||||
if [ -s "$PORTFILE" ]; then
|
||||
# -s: FILE exists and has a size greater than zero
|
||||
ftl_api_port=$(cat "${PORTFILE}")
|
||||
# Exploit prevention: unset the variable if there is malicious content
|
||||
# Verify that the value read from the file is numeric
|
||||
expr "$ftl_api_port" : "[^[:digit:]]" > /dev/null && unset ftl_api_port
|
||||
fi
|
||||
|
||||
# echo the port found in the portfile or default to the default port
|
||||
echo "${ftl_api_port:=$DEFAULT_FTL_PORT}"
|
||||
}
|
@@ -13,10 +13,6 @@ DEFAULT="-1"
|
||||
COREGITDIR="/etc/.pihole/"
|
||||
WEBGITDIR="/var/www/html/admin/"
|
||||
|
||||
# Source the setupvars config file
|
||||
# shellcheck disable=SC1091
|
||||
source /etc/pihole/setupVars.conf
|
||||
|
||||
getLocalVersion() {
|
||||
# FTL requires a different method
|
||||
if [[ "$1" == "FTL" ]]; then
|
||||
@@ -95,11 +91,10 @@ getRemoteVersion(){
|
||||
#If the above file exists, then we can read from that. Prevents overuse of GitHub API
|
||||
if [[ -f "$cachedVersions" ]]; then
|
||||
IFS=' ' read -r -a arrCache < "$cachedVersions"
|
||||
|
||||
case $daemon in
|
||||
"pi-hole" ) echo "${arrCache[0]}";;
|
||||
"AdminLTE" ) [[ "${INSTALL_WEB_INTERFACE}" == true ]] && echo "${arrCache[1]}";;
|
||||
"FTL" ) [[ "${INSTALL_WEB_INTERFACE}" == true ]] && echo "${arrCache[2]}" || echo "${arrCache[1]}";;
|
||||
"pi-hole" ) echo "${arrCache[0]}";;
|
||||
"AdminLTE" ) echo "${arrCache[1]}";;
|
||||
"FTL" ) echo "${arrCache[2]}";;
|
||||
esac
|
||||
|
||||
return 0
|
||||
@@ -122,7 +117,7 @@ getLocalBranch(){
|
||||
local directory="${1}"
|
||||
local branch
|
||||
|
||||
# Local FTL btranch is stored in /etc/pihole/ftlbranch
|
||||
# Local FTL btranch is stored in /etc/pihole/ftlbranch
|
||||
if [[ "$1" == "FTL" ]]; then
|
||||
branch="$(pihole-FTL branch)"
|
||||
else
|
||||
@@ -145,11 +140,6 @@ getLocalBranch(){
|
||||
}
|
||||
|
||||
versionOutput() {
|
||||
if [[ "$1" == "AdminLTE" && "${INSTALL_WEB_INTERFACE}" != true ]]; then
|
||||
echo " WebAdmin not installed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
[[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
|
||||
[[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
|
||||
[[ "$1" == "FTL" ]] && GITDIR="FTL"
|
||||
@@ -163,7 +153,7 @@ versionOutput() {
|
||||
if [[ -n "$current" ]] && [[ -n "$latest" ]]; then
|
||||
output="${1^} version is $branch$current (Latest: $latest)"
|
||||
elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then
|
||||
output="Current ${1^} version is $branch$current"
|
||||
output="Current ${1^} version is $branch$current."
|
||||
elif [[ -z "$current" ]] && [[ -n "$latest" ]]; then
|
||||
output="Latest ${1^} version is $latest"
|
||||
elif [[ "$curHash" == "N/A" ]] || [[ "$latHash" == "N/A" ]]; then
|
||||
@@ -176,7 +166,6 @@ versionOutput() {
|
||||
output="Latest ${1^} hash is $latHash"
|
||||
else
|
||||
errorOutput
|
||||
return 1
|
||||
fi
|
||||
|
||||
[[ -n "$output" ]] && echo " $output"
|
||||
@@ -188,6 +177,10 @@ errorOutput() {
|
||||
}
|
||||
|
||||
defaultOutput() {
|
||||
# Source the setupvars config file
|
||||
# shellcheck disable=SC1091
|
||||
source /etc/pihole/setupVars.conf
|
||||
|
||||
versionOutput "pi-hole" "$@"
|
||||
|
||||
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||
|
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC1090
|
||||
# shellcheck disable=SC2154
|
||||
|
||||
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
@@ -28,9 +26,6 @@ readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||
PH_TEST="true"
|
||||
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||
|
||||
utilsfile="/opt/pihole/utils.sh"
|
||||
source "${utilsfile}"
|
||||
|
||||
coltable="/opt/pihole/COL_TABLE"
|
||||
if [[ -f ${coltable} ]]; then
|
||||
source ${coltable}
|
||||
@@ -42,49 +37,53 @@ Example: pihole -a -p password
|
||||
Set options for the Admin Console
|
||||
|
||||
Options:
|
||||
-p, password Set Admin Console password
|
||||
-c, celsius Set Celsius as preferred temperature unit
|
||||
-f, fahrenheit Set Fahrenheit as preferred temperature unit
|
||||
-k, kelvin Set Kelvin as preferred temperature unit
|
||||
-e, email Set an administrative contact address for the Block Page
|
||||
-h, --help Show this help dialog
|
||||
-i, interface Specify dnsmasq's interface listening behavior
|
||||
-l, privacylevel Set privacy level (0 = lowest, 3 = highest)
|
||||
-t, teleporter Backup configuration as an archive
|
||||
-t, teleporter myname.tar.gz Backup configuration to archive with name myname.tar.gz as specified"
|
||||
-p, password Set Admin Console password
|
||||
-c, celsius Set Celsius as preferred temperature unit
|
||||
-f, fahrenheit Set Fahrenheit as preferred temperature unit
|
||||
-k, kelvin Set Kelvin as preferred temperature unit
|
||||
-e, email Set an administrative contact address for the Block Page
|
||||
-h, --help Show this help dialog
|
||||
-i, interface Specify dnsmasq's interface listening behavior
|
||||
-l, privacylevel Set privacy level (0 = lowest, 4 = highest)"
|
||||
exit 0
|
||||
}
|
||||
|
||||
add_setting() {
|
||||
addOrEditKeyValPair "${setupVars}" "${1}" "${2}"
|
||||
echo "${1}=${2}" >> "${setupVars}"
|
||||
}
|
||||
|
||||
delete_setting() {
|
||||
removeKey "${setupVars}" "${1}"
|
||||
sed -i "/${1}/d" "${setupVars}"
|
||||
}
|
||||
|
||||
change_setting() {
|
||||
addOrEditKeyValPair "${setupVars}" "${1}" "${2}"
|
||||
delete_setting "${1}"
|
||||
add_setting "${1}" "${2}"
|
||||
}
|
||||
|
||||
addFTLsetting() {
|
||||
addOrEditKeyValPair "${FTLconf}" "${1}" "${2}"
|
||||
echo "${1}=${2}" >> "${FTLconf}"
|
||||
}
|
||||
|
||||
deleteFTLsetting() {
|
||||
removeKey "${FTLconf}" "${1}"
|
||||
sed -i "/${1}/d" "${FTLconf}"
|
||||
}
|
||||
|
||||
changeFTLsetting() {
|
||||
addOrEditKeyValPair "${FTLconf}" "${1}" "${2}"
|
||||
deleteFTLsetting "${1}"
|
||||
addFTLsetting "${1}" "${2}"
|
||||
}
|
||||
|
||||
add_dnsmasq_setting() {
|
||||
addOrEditKeyValPair "${dnsmasqconfig}" "${1}" "${2}"
|
||||
if [[ "${2}" != "" ]]; then
|
||||
echo "${1}=${2}" >> "${dnsmasqconfig}"
|
||||
else
|
||||
echo "${1}" >> "${dnsmasqconfig}"
|
||||
fi
|
||||
}
|
||||
|
||||
delete_dnsmasq_setting() {
|
||||
removeKey "${dnsmasqconfig}" "${1}"
|
||||
sed -i "/${1}/d" "${dnsmasqconfig}"
|
||||
}
|
||||
|
||||
SetTemperatureUnit() {
|
||||
@@ -122,14 +121,14 @@ SetWebPassword() {
|
||||
read -s -r -p "Enter New Password (Blank for no password): " PASSWORD
|
||||
echo ""
|
||||
|
||||
if [ "${PASSWORD}" == "" ]; then
|
||||
change_setting "WEBPASSWORD" ""
|
||||
echo -e " ${TICK} Password Removed"
|
||||
exit 0
|
||||
fi
|
||||
if [ "${PASSWORD}" == "" ]; then
|
||||
change_setting "WEBPASSWORD" ""
|
||||
echo -e " ${TICK} Password Removed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
read -s -r -p "Confirm Password: " CONFIRM
|
||||
echo ""
|
||||
read -s -r -p "Confirm Password: " CONFIRM
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
|
||||
@@ -168,11 +167,9 @@ ProcessDNSSettings() {
|
||||
fi
|
||||
|
||||
delete_dnsmasq_setting "domain-needed"
|
||||
delete_dnsmasq_setting "expand-hosts"
|
||||
|
||||
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
|
||||
add_dnsmasq_setting "domain-needed"
|
||||
add_dnsmasq_setting "expand-hosts"
|
||||
fi
|
||||
|
||||
delete_dnsmasq_setting "bogus-priv"
|
||||
@@ -182,7 +179,7 @@ ProcessDNSSettings() {
|
||||
fi
|
||||
|
||||
delete_dnsmasq_setting "dnssec"
|
||||
delete_dnsmasq_setting "trust-anchor"
|
||||
delete_dnsmasq_setting "trust-anchor="
|
||||
|
||||
if [[ "${DNSSEC}" == true ]]; then
|
||||
echo "dnssec
|
||||
@@ -199,8 +196,6 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
|
||||
# Setup interface listening behavior of dnsmasq
|
||||
delete_dnsmasq_setting "interface"
|
||||
delete_dnsmasq_setting "local-service"
|
||||
delete_dnsmasq_setting "except-interface"
|
||||
delete_dnsmasq_setting "bind-interfaces"
|
||||
|
||||
if [[ "${DNSMASQ_LISTENING}" == "all" ]]; then
|
||||
# Listen on all interfaces, permit all origins
|
||||
@@ -209,7 +204,6 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
|
||||
# Listen only on all interfaces, but only local subnets
|
||||
add_dnsmasq_setting "local-service"
|
||||
else
|
||||
# Options "bind" and "single"
|
||||
# Listen only on one interface
|
||||
# Use eth0 as fallback interface if interface is missing in setupVars.conf
|
||||
if [ -z "${PIHOLE_INTERFACE}" ]; then
|
||||
@@ -217,21 +211,10 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
|
||||
fi
|
||||
|
||||
add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
|
||||
|
||||
if [[ "${DNSMASQ_LISTENING}" == "bind" ]]; then
|
||||
# Really bind to interface
|
||||
add_dnsmasq_setting "bind-interfaces"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${CONDITIONAL_FORWARDING}" == true ]]; then
|
||||
# Convert legacy "conditional forwarding" to rev-server configuration
|
||||
# Remove any existing REV_SERVER settings
|
||||
delete_setting "REV_SERVER"
|
||||
delete_setting "REV_SERVER_DOMAIN"
|
||||
delete_setting "REV_SERVER_TARGET"
|
||||
delete_setting "REV_SERVER_CIDR"
|
||||
|
||||
REV_SERVER=true
|
||||
add_setting "REV_SERVER" "true"
|
||||
|
||||
@@ -241,63 +224,30 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
|
||||
REV_SERVER_TARGET="${CONDITIONAL_FORWARDING_IP}"
|
||||
add_setting "REV_SERVER_TARGET" "${REV_SERVER_TARGET}"
|
||||
|
||||
#Convert CONDITIONAL_FORWARDING_REVERSE if necessary e.g:
|
||||
# 1.1.168.192.in-addr.arpa to 192.168.1.1/32
|
||||
# 1.168.192.in-addr.arpa to 192.168.1.0/24
|
||||
# 168.192.in-addr.arpa to 192.168.0.0/16
|
||||
# 192.in-addr.arpa to 192.0.0.0/8
|
||||
if [[ "${CONDITIONAL_FORWARDING_REVERSE}" == *"in-addr.arpa" ]];then
|
||||
arrRev=("${CONDITIONAL_FORWARDING_REVERSE//./ }")
|
||||
case ${#arrRev[@]} in
|
||||
6 ) REV_SERVER_CIDR="${arrRev[3]}.${arrRev[2]}.${arrRev[1]}.${arrRev[0]}/32";;
|
||||
5 ) REV_SERVER_CIDR="${arrRev[2]}.${arrRev[1]}.${arrRev[0]}.0/24";;
|
||||
4 ) REV_SERVER_CIDR="${arrRev[1]}.${arrRev[0]}.0.0/16";;
|
||||
3 ) REV_SERVER_CIDR="${arrRev[0]}.0.0.0/8";;
|
||||
esac
|
||||
else
|
||||
# Set REV_SERVER_CIDR to whatever value it was set to
|
||||
REV_SERVER_CIDR="${CONDITIONAL_FORWARDING_REVERSE}"
|
||||
fi
|
||||
|
||||
# If REV_SERVER_CIDR is not converted by the above, then use the REV_SERVER_TARGET variable to derive it
|
||||
if [ -z "${REV_SERVER_CIDR}" ]; then
|
||||
# Convert existing input to /24 subnet (preserves legacy behavior)
|
||||
# This sed converts "192.168.1.2" to "192.168.1.0/24"
|
||||
# shellcheck disable=2001
|
||||
REV_SERVER_CIDR="$(sed "s+\\.[0-9]*$+\\.0/24+" <<< "${REV_SERVER_TARGET}")"
|
||||
fi
|
||||
add_setting "REV_SERVER_CIDR" "${REV_SERVER_CIDR}"
|
||||
|
||||
# Remove obsolete settings from setupVars.conf
|
||||
delete_setting "CONDITIONAL_FORWARDING"
|
||||
delete_setting "CONDITIONAL_FORWARDING_REVERSE"
|
||||
delete_setting "CONDITIONAL_FORWARDING_DOMAIN"
|
||||
delete_setting "CONDITIONAL_FORWARDING_IP"
|
||||
fi
|
||||
|
||||
delete_dnsmasq_setting "rev-server"
|
||||
# Convert existing input to /24 subnet (preserves legacy behavior)
|
||||
# This sed converts "192.168.1.2" to "192.168.1.0/24"
|
||||
# shellcheck disable=2001
|
||||
REV_SERVER_CIDR="$(sed "s+\\.[0-9]*$+\\.0/24+" <<< "${REV_SERVER_TARGET}")"
|
||||
add_setting "REV_SERVER_CIDR" "${REV_SERVER_CIDR}"
|
||||
fi
|
||||
|
||||
if [[ "${REV_SERVER}" == true ]]; then
|
||||
add_dnsmasq_setting "rev-server=${REV_SERVER_CIDR},${REV_SERVER_TARGET}"
|
||||
if [ -n "${REV_SERVER_DOMAIN}" ]; then
|
||||
# Forward local domain names to the CF target, too
|
||||
add_dnsmasq_setting "server=/${REV_SERVER_DOMAIN}/${REV_SERVER_TARGET}"
|
||||
fi
|
||||
|
||||
if [[ "${DNS_FQDN_REQUIRED}" != true ]]; then
|
||||
# Forward unqualified names to the CF target only when the "never
|
||||
# forward non-FQDN" option is unticked
|
||||
add_dnsmasq_setting "server=//${REV_SERVER_TARGET}"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# We need to process DHCP settings here as well to account for possible
|
||||
# changes in the non-FQDN forwarding. This cannot be done in 01-pihole.conf
|
||||
# as we don't want to delete all local=/.../ lines so it's much safer to
|
||||
# simply rewrite the entire corresponding config file (which is what the
|
||||
# DHCP settings subroutie is doing)
|
||||
ProcessDHCPSettings
|
||||
# Prevent Firefox from automatically switching over to DNS-over-HTTPS
|
||||
# This follows https://support.mozilla.org/en-US/kb/configuring-networks-disable-dns-over-https
|
||||
# (sourced 7th September 2019)
|
||||
add_dnsmasq_setting "server=/use-application-dns.net/"
|
||||
}
|
||||
|
||||
SetDNSServers() {
|
||||
@@ -379,34 +329,34 @@ ProcessDHCPSettings() {
|
||||
source "${setupVars}"
|
||||
|
||||
if [[ "${DHCP_ACTIVE}" == "true" ]]; then
|
||||
interface="${PIHOLE_INTERFACE}"
|
||||
interface="${PIHOLE_INTERFACE}"
|
||||
|
||||
# Use eth0 as fallback interface
|
||||
if [ -z ${interface} ]; then
|
||||
interface="eth0"
|
||||
fi
|
||||
# Use eth0 as fallback interface
|
||||
if [ -z ${interface} ]; then
|
||||
interface="eth0"
|
||||
fi
|
||||
|
||||
if [[ "${PIHOLE_DOMAIN}" == "" ]]; then
|
||||
PIHOLE_DOMAIN="lan"
|
||||
change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}"
|
||||
fi
|
||||
if [[ "${PIHOLE_DOMAIN}" == "" ]]; then
|
||||
PIHOLE_DOMAIN="lan"
|
||||
change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}"
|
||||
fi
|
||||
|
||||
if [[ "${DHCP_LEASETIME}" == "0" ]]; then
|
||||
leasetime="infinite"
|
||||
elif [[ "${DHCP_LEASETIME}" == "" ]]; then
|
||||
leasetime="24"
|
||||
change_setting "DHCP_LEASETIME" "${leasetime}"
|
||||
elif [[ "${DHCP_LEASETIME}" == "24h" ]]; then
|
||||
#Installation is affected by known bug, introduced in a previous version.
|
||||
#This will automatically clean up setupVars.conf and remove the unnecessary "h"
|
||||
leasetime="24"
|
||||
change_setting "DHCP_LEASETIME" "${leasetime}"
|
||||
else
|
||||
leasetime="${DHCP_LEASETIME}h"
|
||||
fi
|
||||
if [[ "${DHCP_LEASETIME}" == "0" ]]; then
|
||||
leasetime="infinite"
|
||||
elif [[ "${DHCP_LEASETIME}" == "" ]]; then
|
||||
leasetime="24"
|
||||
change_setting "DHCP_LEASETIME" "${leasetime}"
|
||||
elif [[ "${DHCP_LEASETIME}" == "24h" ]]; then
|
||||
#Installation is affected by known bug, introduced in a previous version.
|
||||
#This will automatically clean up setupVars.conf and remove the unnecessary "h"
|
||||
leasetime="24"
|
||||
change_setting "DHCP_LEASETIME" "${leasetime}"
|
||||
else
|
||||
leasetime="${DHCP_LEASETIME}h"
|
||||
fi
|
||||
|
||||
# Write settings to file
|
||||
echo "###############################################################################
|
||||
# Write settings to file
|
||||
echo "###############################################################################
|
||||
# DHCP SERVER CONFIG FILE AUTOMATICALLY POPULATED BY PI-HOLE WEB INTERFACE. #
|
||||
# ANY CHANGES MADE TO THIS FILE WILL BE LOST ON CHANGE #
|
||||
###############################################################################
|
||||
@@ -416,34 +366,26 @@ dhcp-option=option:router,${DHCP_ROUTER}
|
||||
dhcp-leasefile=/etc/pihole/dhcp.leases
|
||||
#quiet-dhcp
|
||||
" > "${dhcpconfig}"
|
||||
chmod 644 "${dhcpconfig}"
|
||||
chmod 644 "${dhcpconfig}"
|
||||
|
||||
if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
|
||||
echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
|
||||
if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
|
||||
echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
|
||||
fi
|
||||
|
||||
# When there is a Pi-hole domain set and "Never forward non-FQDNs" is
|
||||
# ticked, we add `local=/domain/` to tell FTL that this domain is purely
|
||||
# local and FTL may answer queries from /etc/hosts or DHCP but should
|
||||
# never forward queries on that domain to any upstream servers
|
||||
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
|
||||
echo "local=/${PIHOLE_DOMAIN}/" >> "${dhcpconfig}"
|
||||
fi
|
||||
fi
|
||||
# Sourced from setupVars
|
||||
# shellcheck disable=SC2154
|
||||
if [[ "${DHCP_rapid_commit}" == "true" ]]; then
|
||||
echo "dhcp-rapid-commit" >> "${dhcpconfig}"
|
||||
fi
|
||||
|
||||
# Sourced from setupVars
|
||||
# shellcheck disable=SC2154
|
||||
if [[ "${DHCP_rapid_commit}" == "true" ]]; then
|
||||
echo "dhcp-rapid-commit" >> "${dhcpconfig}"
|
||||
fi
|
||||
|
||||
if [[ "${DHCP_IPv6}" == "true" ]]; then
|
||||
echo "#quiet-dhcp6
|
||||
if [[ "${DHCP_IPv6}" == "true" ]]; then
|
||||
echo "#quiet-dhcp6
|
||||
#enable-ra
|
||||
dhcp-option=option6:dns-server,[::]
|
||||
dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,64,3600
|
||||
dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,${leasetime}
|
||||
ra-param=*,0,0
|
||||
" >> "${dhcpconfig}"
|
||||
fi
|
||||
fi
|
||||
|
||||
else
|
||||
if [[ -f "${dhcpconfig}" ]]; then
|
||||
@@ -500,15 +442,10 @@ SetWebUITheme() {
|
||||
}
|
||||
|
||||
CheckUrl(){
|
||||
local regex check_url
|
||||
local regex
|
||||
# Check for characters NOT allowed in URLs
|
||||
regex="[^a-zA-Z0-9:/?&%=~._()-;]"
|
||||
|
||||
# this will remove first @ that is after schema and before domain
|
||||
# \1 is optional schema, \2 is userinfo
|
||||
check_url="$( sed -re 's#([^:/]*://)?([^/]+)@#\1\2#' <<< "$1" )"
|
||||
|
||||
if [[ "${check_url}" =~ ${regex} ]]; then
|
||||
regex="[^a-zA-Z0-9:/?&%=~._-]"
|
||||
if [[ "${1}" =~ ${regex} ]]; then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
@@ -523,13 +460,13 @@ CustomizeAdLists() {
|
||||
|
||||
if CheckUrl "${address}"; then
|
||||
if [[ "${args[2]}" == "enable" ]]; then
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "UPDATE adlist SET enabled = 1 WHERE address = '${address}'"
|
||||
sqlite3 "${gravityDBfile}" "UPDATE adlist SET enabled = 1 WHERE address = '${address}'"
|
||||
elif [[ "${args[2]}" == "disable" ]]; then
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "UPDATE adlist SET enabled = 0 WHERE address = '${address}'"
|
||||
sqlite3 "${gravityDBfile}" "UPDATE adlist SET enabled = 0 WHERE address = '${address}'"
|
||||
elif [[ "${args[2]}" == "add" ]]; then
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "INSERT OR IGNORE INTO adlist (address, comment) VALUES ('${address}', '${comment}')"
|
||||
sqlite3 "${gravityDBfile}" "INSERT OR IGNORE INTO adlist (address, comment) VALUES ('${address}', '${comment}')"
|
||||
elif [[ "${args[2]}" == "del" ]]; then
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "DELETE FROM adlist WHERE address = '${address}'"
|
||||
sqlite3 "${gravityDBfile}" "DELETE FROM adlist WHERE address = '${address}'"
|
||||
else
|
||||
echo "Not permitted"
|
||||
return 1
|
||||
@@ -540,6 +477,25 @@ CustomizeAdLists() {
|
||||
fi
|
||||
}
|
||||
|
||||
SetPrivacyMode() {
|
||||
if [[ "${args[2]}" == "true" ]]; then
|
||||
change_setting "API_PRIVACY_MODE" "true"
|
||||
else
|
||||
change_setting "API_PRIVACY_MODE" "false"
|
||||
fi
|
||||
}
|
||||
|
||||
ResolutionSettings() {
|
||||
typ="${args[2]}"
|
||||
state="${args[3]}"
|
||||
|
||||
if [[ "${typ}" == "forward" ]]; then
|
||||
change_setting "API_GET_UPSTREAM_DNS_HOSTNAME" "${state}"
|
||||
elif [[ "${typ}" == "clients" ]]; then
|
||||
change_setting "API_GET_CLIENT_HOSTNAME" "${state}"
|
||||
fi
|
||||
}
|
||||
|
||||
AddDHCPStaticAddress() {
|
||||
mac="${args[2]}"
|
||||
ip="${args[3]}"
|
||||
@@ -559,13 +515,7 @@ AddDHCPStaticAddress() {
|
||||
|
||||
RemoveDHCPStaticAddress() {
|
||||
mac="${args[2]}"
|
||||
if [[ "$mac" =~ ^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$ ]]; then
|
||||
sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}"
|
||||
else
|
||||
echo " ${CROSS} Invalid Mac Passed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}"
|
||||
}
|
||||
|
||||
SetAdminEmail() {
|
||||
@@ -608,13 +558,12 @@ Example: 'pihole -a -i local'
|
||||
Specify dnsmasq's network interface listening behavior
|
||||
|
||||
Interfaces:
|
||||
local Only respond to queries from devices that
|
||||
are at most one hop away (local devices)
|
||||
single Respond only on interface ${PIHOLE_INTERFACE}
|
||||
bind Bind only on interface ${PIHOLE_INTERFACE}
|
||||
local Listen on all interfaces, but only allow queries from
|
||||
devices that are at most one hop away (local devices)
|
||||
single Listen only on ${PIHOLE_INTERFACE} interface
|
||||
all Listen on all interfaces, permit all origins"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${args[2]}" == "all" ]]; then
|
||||
echo -e " ${INFO} Listening on all interfaces, permitting all origins. Please use a firewall!"
|
||||
@@ -622,9 +571,6 @@ Interfaces:
|
||||
elif [[ "${args[2]}" == "local" ]]; then
|
||||
echo -e " ${INFO} Listening on all interfaces, permitting origins from one hop away (LAN)"
|
||||
change_setting "DNSMASQ_LISTENING" "local"
|
||||
elif [[ "${args[2]}" == "bind" ]]; then
|
||||
echo -e " ${INFO} Binding on interface ${PIHOLE_INTERFACE}"
|
||||
change_setting "DNSMASQ_LISTENING" "bind"
|
||||
else
|
||||
echo -e " ${INFO} Listening only on interface ${PIHOLE_INTERFACE}"
|
||||
change_setting "DNSMASQ_LISTENING" "single"
|
||||
@@ -640,17 +586,9 @@ Interfaces:
|
||||
}
|
||||
|
||||
Teleporter() {
|
||||
local filename
|
||||
filename="${args[2]}"
|
||||
if [[ -z "${filename}" ]]; then
|
||||
local datetimestamp
|
||||
local host
|
||||
datetimestamp=$(date "+%Y-%m-%d_%H-%M-%S")
|
||||
host=$(hostname)
|
||||
host="${host//./_}"
|
||||
filename="pi-hole-${host:-noname}-teleporter_${datetimestamp}.tar.gz"
|
||||
fi
|
||||
php /var/www/html/admin/scripts/pi-hole/php/teleporter.php > "${filename}"
|
||||
local datetimestamp
|
||||
datetimestamp=$(date "+%Y-%m-%d_%H-%M-%S")
|
||||
php /var/www/html/admin/scripts/pi-hole/php/teleporter.php > "pi-hole-teleporter_${datetimestamp}.tar.gz"
|
||||
}
|
||||
|
||||
checkDomain()
|
||||
@@ -671,32 +609,32 @@ addAudit()
|
||||
domains=""
|
||||
for domain in "$@"
|
||||
do
|
||||
# Check domain to be added. Only continue if it is valid
|
||||
validDomain="$(checkDomain "${domain}")"
|
||||
if [[ -n "${validDomain}" ]]; then
|
||||
# Put comma in between domains when there is
|
||||
# more than one domains to be added
|
||||
# SQL INSERT allows adding multiple rows at once using the format
|
||||
## INSERT INTO table (domain) VALUES ('abc.de'),('fgh.ij'),('klm.no'),('pqr.st');
|
||||
if [[ -n "${domains}" ]]; then
|
||||
domains="${domains},"
|
||||
fi
|
||||
domains="${domains}('${domain}')"
|
||||
# Check domain to be added. Only continue if it is valid
|
||||
validDomain="$(checkDomain "${domain}")"
|
||||
if [[ -n "${validDomain}" ]]; then
|
||||
# Put comma in between domains when there is
|
||||
# more than one domains to be added
|
||||
# SQL INSERT allows adding multiple rows at once using the format
|
||||
## INSERT INTO table (domain) VALUES ('abc.de'),('fgh.ij'),('klm.no'),('pqr.st');
|
||||
if [[ -n "${domains}" ]]; then
|
||||
domains="${domains},"
|
||||
fi
|
||||
domains="${domains}('${domain}')"
|
||||
fi
|
||||
done
|
||||
# Insert only the domain here. The date_added field will be
|
||||
# filled with its default value (date_added = current timestamp)
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "INSERT INTO domain_audit (domain) VALUES ${domains};"
|
||||
sqlite3 "${gravityDBfile}" "INSERT INTO domain_audit (domain) VALUES ${domains};"
|
||||
}
|
||||
|
||||
clearAudit()
|
||||
{
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "DELETE FROM domain_audit;"
|
||||
sqlite3 "${gravityDBfile}" "DELETE FROM domain_audit;"
|
||||
}
|
||||
|
||||
SetPrivacyLevel() {
|
||||
# Set privacy level. Minimum is 0, maximum is 3
|
||||
if [ "${args[2]}" -ge 0 ] && [ "${args[2]}" -le 3 ]; then
|
||||
# Set privacy level. Minimum is 0, maximum is 4
|
||||
if [ "${args[2]}" -ge 0 ] && [ "${args[2]}" -le 4 ]; then
|
||||
changeFTLsetting "PRIVACYLEVEL" "${args[2]}"
|
||||
pihole restartdns reload-lists
|
||||
fi
|
||||
@@ -707,25 +645,10 @@ AddCustomDNSAddress() {
|
||||
|
||||
ip="${args[2]}"
|
||||
host="${args[3]}"
|
||||
reload="${args[4]}"
|
||||
echo "${ip} ${host}" >> "${dnscustomfile}"
|
||||
|
||||
validHost="$(checkDomain "${host}")"
|
||||
if [[ -n "${validHost}" ]]; then
|
||||
if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
|
||||
echo "${ip} ${validHost}" >> "${dnscustomfile}"
|
||||
else
|
||||
echo -e " ${CROSS} Invalid IP has been passed"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo " ${CROSS} Invalid Domain passed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Restart dnsmasq to load new custom DNS entries only if $reload not false
|
||||
if [[ ! $reload == "false" ]]; then
|
||||
RestartDNS
|
||||
fi
|
||||
# Restart dnsmasq to load new custom DNS entries
|
||||
RestartDNS
|
||||
}
|
||||
|
||||
RemoveCustomDNSAddress() {
|
||||
@@ -733,25 +656,10 @@ RemoveCustomDNSAddress() {
|
||||
|
||||
ip="${args[2]}"
|
||||
host="${args[3]}"
|
||||
reload="${args[4]}"
|
||||
sed -i "/${ip} ${host}/d" "${dnscustomfile}"
|
||||
|
||||
validHost="$(checkDomain "${host}")"
|
||||
if [[ -n "${validHost}" ]]; then
|
||||
if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
|
||||
sed -i "/^${ip} ${validHost}$/Id" "${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 is not false
|
||||
if [[ ! $reload == "false" ]]; then
|
||||
RestartDNS
|
||||
fi
|
||||
# Restart dnsmasq to update removed custom DNS entries
|
||||
RestartDNS
|
||||
}
|
||||
|
||||
AddCustomCNAMERecord() {
|
||||
@@ -759,25 +667,10 @@ AddCustomCNAMERecord() {
|
||||
|
||||
domain="${args[2]}"
|
||||
target="${args[3]}"
|
||||
reload="${args[4]}"
|
||||
echo "cname=${domain},${target}" >> "${dnscustomcnamefile}"
|
||||
|
||||
validDomain="$(checkDomain "${domain}")"
|
||||
if [[ -n "${validDomain}" ]]; then
|
||||
validTarget="$(checkDomain "${target}")"
|
||||
if [[ -n "${validTarget}" ]]; then
|
||||
echo "cname=${validDomain},${validTarget}" >> "${dnscustomcnamefile}"
|
||||
else
|
||||
echo " ${CROSS} Invalid Target Passed!"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo " ${CROSS} Invalid Domain passed!"
|
||||
exit 1
|
||||
fi
|
||||
# Restart dnsmasq to load new custom CNAME records only if reload is not false
|
||||
if [[ ! $reload == "false" ]]; then
|
||||
RestartDNS
|
||||
fi
|
||||
# Restart dnsmasq to load new custom CNAME records
|
||||
RestartDNS
|
||||
}
|
||||
|
||||
RemoveCustomCNAMERecord() {
|
||||
@@ -785,43 +678,10 @@ RemoveCustomCNAMERecord() {
|
||||
|
||||
domain="${args[2]}"
|
||||
target="${args[3]}"
|
||||
reload="${args[4]}"
|
||||
sed -i "/cname=${domain},${target}/d" "${dnscustomcnamefile}"
|
||||
|
||||
validDomain="$(checkDomain "${domain}")"
|
||||
if [[ -n "${validDomain}" ]]; then
|
||||
validTarget="$(checkDomain "${target}")"
|
||||
if [[ -n "${validTarget}" ]]; then
|
||||
sed -i "/cname=${validDomain},${validTarget}$/Id" "${dnscustomcnamefile}"
|
||||
else
|
||||
echo " ${CROSS} Invalid Target Passed!"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo " ${CROSS} Invalid Domain passed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Restart dnsmasq to update removed custom CNAME records only if $reload not false
|
||||
if [[ ! $reload == "false" ]]; then
|
||||
RestartDNS
|
||||
fi
|
||||
}
|
||||
|
||||
SetRateLimit() {
|
||||
local rate_limit_count rate_limit_interval reload
|
||||
rate_limit_count="${args[2]}"
|
||||
rate_limit_interval="${args[3]}"
|
||||
reload="${args[4]}"
|
||||
|
||||
# Set rate-limit setting inf valid
|
||||
if [ "${rate_limit_count}" -ge 0 ] && [ "${rate_limit_interval}" -ge 0 ]; then
|
||||
changeFTLsetting "RATE_LIMIT" "${rate_limit_count}/${rate_limit_interval}"
|
||||
fi
|
||||
|
||||
# Restart FTL to update rate-limit settings only if $reload not false
|
||||
if [[ ! $reload == "false" ]]; then
|
||||
RestartDNS
|
||||
fi
|
||||
# Restart dnsmasq to update removed custom CNAME records
|
||||
RestartDNS
|
||||
}
|
||||
|
||||
main() {
|
||||
@@ -844,6 +704,8 @@ main() {
|
||||
"layout" ) SetWebUILayout;;
|
||||
"theme" ) SetWebUITheme;;
|
||||
"-h" | "--help" ) helpFunc;;
|
||||
"privacymode" ) SetPrivacyMode;;
|
||||
"resolve" ) ResolutionSettings;;
|
||||
"addstaticdhcp" ) AddDHCPStaticAddress;;
|
||||
"removestaticdhcp" ) RemoveDHCPStaticAddress;;
|
||||
"-e" | "email" ) SetAdminEmail "$3";;
|
||||
@@ -857,7 +719,6 @@ main() {
|
||||
"removecustomdns" ) RemoveCustomDNSAddress;;
|
||||
"addcustomcname" ) AddCustomCNAMERecord;;
|
||||
"removecustomcname" ) RemoveCustomCNAMERecord;;
|
||||
"ratelimit" ) SetRateLimit;;
|
||||
* ) helpFunc;;
|
||||
esac
|
||||
|
||||
|
28
advanced/Scripts/wildcard_regex_converter.sh
Normal file
28
advanced/Scripts/wildcard_regex_converter.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
# Network-wide ad blocking via your own hardware.
|
||||
#
|
||||
# Provides an automated migration subroutine to convert Pi-hole v3.x wildcard domains to Pi-hole v4.x regex filters
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
# regexFile set in gravity.sh
|
||||
|
||||
wildcardFile="/etc/dnsmasq.d/03-pihole-wildcard.conf"
|
||||
|
||||
convert_wildcard_to_regex() {
|
||||
if [ ! -f "${wildcardFile}" ]; then
|
||||
return
|
||||
fi
|
||||
local addrlines domains uniquedomains
|
||||
# Obtain wildcard domains from old file
|
||||
addrlines="$(grep -oE "/.*/" ${wildcardFile})"
|
||||
# Strip "/" from domain names and convert "." to regex-compatible "\."
|
||||
domains="$(sed 's/\///g;s/\./\\./g' <<< "${addrlines}")"
|
||||
# Remove repeated domains (may have been inserted two times due to A and AAAA blocking)
|
||||
uniquedomains="$(uniq <<< "${domains}")"
|
||||
# Automatically generate regex filters and remove old wildcards file
|
||||
awk '{print "(^|\\.)"$0"$"}' <<< "${uniquedomains}" >> "${regexFile:?}" && rm "${wildcardFile}"
|
||||
}
|
@@ -31,11 +31,7 @@ CREATE TABLE adlist
|
||||
enabled BOOLEAN NOT NULL DEFAULT 1,
|
||||
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||
comment TEXT,
|
||||
date_updated INTEGER,
|
||||
number INTEGER NOT NULL DEFAULT 0,
|
||||
invalid_domains INTEGER NOT NULL DEFAULT 0,
|
||||
status INTEGER NOT NULL DEFAULT 0
|
||||
comment TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE adlist_by_group
|
||||
@@ -57,7 +53,7 @@ CREATE TABLE info
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "info" VALUES('version','15');
|
||||
INSERT INTO "info" VALUES('version','12');
|
||||
|
||||
CREATE TABLE domain_audit
|
||||
(
|
||||
@@ -76,7 +72,7 @@ CREATE TABLE domainlist_by_group
|
||||
CREATE TABLE client
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
ip TEXT NOT NULL UNIQUE,
|
||||
ip TEXT NOL NULL UNIQUE,
|
||||
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||
comment TEXT
|
||||
@@ -89,9 +85,9 @@ CREATE TABLE client_by_group
|
||||
PRIMARY KEY (client_id, group_id)
|
||||
);
|
||||
|
||||
CREATE TRIGGER tr_adlist_update AFTER UPDATE OF address,enabled,comment ON adlist
|
||||
CREATE TRIGGER tr_adlist_update AFTER UPDATE ON adlist
|
||||
BEGIN
|
||||
UPDATE adlist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
||||
UPDATE adlist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE address = NEW.address;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER tr_client_update AFTER UPDATE ON client
|
||||
@@ -143,10 +139,12 @@ CREATE VIEW vw_gravity AS SELECT domain, adlist_by_group.group_id AS group_id
|
||||
LEFT JOIN "group" ON "group".id = adlist_by_group.group_id
|
||||
WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1);
|
||||
|
||||
CREATE VIEW vw_adlist AS SELECT DISTINCT address, id
|
||||
CREATE VIEW vw_adlist AS SELECT DISTINCT address, adlist.id AS id
|
||||
FROM adlist
|
||||
WHERE enabled = 1
|
||||
ORDER BY id;
|
||||
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = adlist.id
|
||||
LEFT JOIN "group" ON "group".id = adlist_by_group.group_id
|
||||
WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||
ORDER BY adlist.id;
|
||||
|
||||
CREATE TRIGGER tr_domainlist_add AFTER INSERT ON domainlist
|
||||
BEGIN
|
||||
|
@@ -12,17 +12,14 @@ INSERT OR REPLACE INTO "group" SELECT * FROM OLD."group";
|
||||
INSERT OR REPLACE INTO domain_audit SELECT * FROM OLD.domain_audit;
|
||||
|
||||
INSERT OR REPLACE INTO domainlist SELECT * FROM OLD.domainlist;
|
||||
DELETE FROM OLD.domainlist_by_group WHERE domainlist_id NOT IN (SELECT id FROM OLD.domainlist);
|
||||
INSERT OR REPLACE INTO domainlist_by_group SELECT * FROM OLD.domainlist_by_group;
|
||||
|
||||
INSERT OR REPLACE INTO adlist SELECT * FROM OLD.adlist;
|
||||
DELETE FROM OLD.adlist_by_group WHERE adlist_id NOT IN (SELECT id FROM OLD.adlist);
|
||||
INSERT OR REPLACE INTO adlist_by_group SELECT * FROM OLD.adlist_by_group;
|
||||
|
||||
INSERT OR REPLACE INTO info SELECT * FROM OLD.info;
|
||||
|
||||
INSERT OR REPLACE INTO client SELECT * FROM OLD.client;
|
||||
DELETE FROM OLD.client_by_group WHERE client_id NOT IN (SELECT id FROM OLD.client);
|
||||
INSERT OR REPLACE INTO client_by_group SELECT * FROM OLD.client_by_group;
|
||||
|
||||
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#; Pi-hole FTL config file
|
||||
#; Comments should start with #; to avoid issues with PHP and bash reading this file
|
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/usr/bin/env bash
|
||||
### BEGIN INIT INFO
|
||||
# Provides: pihole-FTL
|
||||
# Required-Start: $remote_fs $syslog $network
|
||||
@@ -9,8 +9,11 @@
|
||||
# Description: Enable service provided by pihole-FTL daemon
|
||||
### END INIT INFO
|
||||
|
||||
FTLUSER=pihole
|
||||
PIDFILE=/run/pihole-FTL.pid
|
||||
|
||||
is_running() {
|
||||
pgrep -xo "pihole-FTL" > /dev/null
|
||||
pgrep -o "pihole-FTL" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
|
||||
@@ -20,25 +23,27 @@ start() {
|
||||
echo "pihole-FTL is already running"
|
||||
else
|
||||
# Touch files to ensure they exist (create if non-existing, preserve if existing)
|
||||
mkdir -pm 0755 /run/pihole
|
||||
[ ! -f /run/pihole-FTL.pid ] && install -m 644 -o pihole -g pihole /dev/null /run/pihole-FTL.pid
|
||||
[ ! -f /run/pihole-FTL.port ] && install -m 644 -o pihole -g pihole /dev/null /run/pihole-FTL.port
|
||||
[ ! -f /var/log/pihole-FTL.log ] && install -m 644 -o pihole -g pihole /dev/null /var/log/pihole-FTL.log
|
||||
[ ! -f /var/log/pihole.log ] && install -m 644 -o pihole -g pihole /dev/null /var/log/pihole.log
|
||||
[ ! -f /etc/pihole/dhcp.leases ] && install -m 644 -o pihole -g pihole /dev/null /etc/pihole/dhcp.leases
|
||||
touch /var/log/pihole-FTL.log /var/log/pihole.log
|
||||
touch /run/pihole-FTL.pid /run/pihole-FTL.port
|
||||
touch /etc/pihole/dhcp.leases
|
||||
mkdir -p /run/pihole
|
||||
mkdir -p /var/log/pihole
|
||||
chown pihole:pihole /run/pihole /var/log/pihole
|
||||
# Remove possible leftovers from previous pihole-FTL processes
|
||||
rm -f /dev/shm/FTL-* 2> /dev/null
|
||||
rm /run/pihole/FTL.sock 2> /dev/null
|
||||
# Ensure that permissions are set so that pihole-FTL can edit all necessary files
|
||||
chown pihole:pihole /run/pihole /etc/pihole /var/log/pihole.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 /etc/pihole/dhcp.leases /var/log/pihole-FTL.log /var/log/pihole.log
|
||||
chown pihole:pihole /run/pihole-FTL.pid /run/pihole-FTL.port
|
||||
chown pihole:pihole /etc/pihole /etc/pihole/dhcp.leases 2> /dev/null
|
||||
chown pihole:pihole /var/log/pihole-FTL.log /var/log/pihole.log
|
||||
chmod 0644 /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole.log
|
||||
# Chown database files to the user FTL runs as. We ignore errors as the files may not (yet) exist
|
||||
chown -f pihole:pihole /etc/pihole/pihole-FTL.db /etc/pihole/gravity.db /etc/pihole/macvendor.db
|
||||
# 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
|
||||
chown pihole:pihole /etc/pihole/pihole-FTL.db /etc/pihole/gravity.db 2> /dev/null
|
||||
if setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_NICE+eip "$(which pihole-FTL)"; then
|
||||
su -s /bin/sh -c "/usr/bin/pihole-FTL" "$FTLUSER"
|
||||
else
|
||||
echo "Warning: Starting pihole-FTL as root because setting capabilities is not supported on this system"
|
||||
/usr/bin/pihole-FTL
|
||||
pihole-FTL
|
||||
fi
|
||||
echo
|
||||
fi
|
||||
@@ -47,20 +52,20 @@ start() {
|
||||
# Stop the service
|
||||
stop() {
|
||||
if is_running; then
|
||||
pkill -xo "pihole-FTL"
|
||||
for i in 1 2 3 4 5; do
|
||||
pkill -o pihole-FTL
|
||||
for i in {1..5}; do
|
||||
if ! is_running; then
|
||||
break
|
||||
fi
|
||||
|
||||
printf "."
|
||||
echo -n "."
|
||||
sleep 1
|
||||
done
|
||||
echo
|
||||
|
||||
if is_running; then
|
||||
echo "Not stopped; may still be shutting down or shutdown may have failed, killing now"
|
||||
pkill -xo -9 "pihole-FTL"
|
||||
pkill -o -9 pihole-FTL
|
||||
exit 1
|
||||
else
|
||||
echo "Stopped"
|
||||
@@ -68,8 +73,6 @@ stop() {
|
||||
else
|
||||
echo "Not running"
|
||||
fi
|
||||
# Cleanup
|
||||
rm -f /run/pihole/FTL.sock /dev/shm/FTL-*
|
||||
echo
|
||||
}
|
||||
|
||||
@@ -98,7 +101,7 @@ case "$1" in
|
||||
start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|reload|status}"
|
||||
echo $"Usage: $0 {start|stop|restart|reload|status}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
|
@@ -26,7 +26,7 @@
|
||||
# parameter "quiet": don't print messages
|
||||
00 00 * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole flush once quiet
|
||||
|
||||
@reboot root /usr/sbin/logrotate --state /var/lib/logrotate/pihole /etc/pihole/logrotate
|
||||
@reboot root /usr/sbin/logrotate /etc/pihole/logrotate
|
||||
|
||||
# Pi-hole: Grab local version and branch every 10 minutes
|
||||
*/10 * * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker local
|
||||
|
@@ -56,11 +56,11 @@ _pihole() {
|
||||
;;
|
||||
"privacylevel")
|
||||
if ( [[ "$prev2" == "admin" ]] || [[ "$prev2" == "-a" ]] ); then
|
||||
opts_privacy="0 1 2 3"
|
||||
opts_privacy="0 1 2 3 4"
|
||||
COMPREPLY=( $(compgen -W "${opts_privacy}" -- ${cur}) )
|
||||
else
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
"core"|"admin"|"ftl")
|
||||
if [[ "$prev2" == "checkout" ]]; then
|
||||
|
@@ -145,17 +145,7 @@ body {
|
||||
}
|
||||
|
||||
/* User is greeted with a splash page when browsing to Pi-hole IP address */
|
||||
#splashpage {
|
||||
background: #222;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#splashpage { background: #222; color: rgba(255, 255, 255, 0.7); text-align: center; }
|
||||
#splashpage img { margin: 5px; width: 256px; }
|
||||
#splashpage b { color: inherit; }
|
||||
|
||||
@@ -206,26 +196,6 @@ header #bpAlt label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#pihole_card {
|
||||
width: 400px;
|
||||
height: auto;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
#pihole_card p, #pihole_card a {
|
||||
font-size: 13pt;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#pihole_logo_splash {
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Click anywhere else on screen to hide #bpAbout */
|
||||
#bpAboutToggle:checked {
|
||||
display: block;
|
||||
@@ -412,44 +382,12 @@ footer {
|
||||
|
||||
/* Responsive Content */
|
||||
@media only screen and (max-width: 500px) {
|
||||
h1 a {
|
||||
font-size: 1.8rem;
|
||||
min-width: 170px;
|
||||
}
|
||||
|
||||
footer span::before {
|
||||
content: "Generated ";
|
||||
}
|
||||
|
||||
footer span {
|
||||
display: block;
|
||||
}
|
||||
h1 a { font-size: 1.8rem; min-width: 170px; }
|
||||
footer span::before { content: "Generated "; }
|
||||
footer span { display: block; }
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1251px) {
|
||||
#bpWrapper, footer {
|
||||
border-radius: 0 0 5px 5px;
|
||||
}
|
||||
|
||||
#bpAbout {
|
||||
border-right-width: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 400px) {
|
||||
#pihole_card {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#pihole_card p, #pihole_card a {
|
||||
font-size: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 256px) {
|
||||
#pihole_logo_splash {
|
||||
width: 90% !important;
|
||||
height: auto;
|
||||
}
|
||||
#bpWrapper, footer { border-radius: 0 0 5px 5px; }
|
||||
#bpAbout { border-right-width: 1px; }
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ unset($setupVars);
|
||||
$landPage = "../landing.php";
|
||||
|
||||
// Define array for hostnames to be accepted as self address for splash page
|
||||
$authorizedHosts = [ "localhost" ];
|
||||
$authorizedHosts = [];
|
||||
if (!empty($_SERVER["FQDN"])) {
|
||||
// If setenv.add-environment = ("fqdn" => "true") is configured in lighttpd,
|
||||
// append $serverName to $authorizedHosts
|
||||
@@ -55,37 +55,34 @@ if ($serverName === "pi.hole"
|
||||
// Redirect to Web Interface
|
||||
exit(header("Location: /admin"));
|
||||
} elseif (filter_var($serverName, FILTER_VALIDATE_IP) || in_array($serverName, $authorizedHosts)) {
|
||||
// When directly browsing via IP or authorized hostname
|
||||
// Render splash/landing page based off presence of $landPage file
|
||||
// Unset variables so as to not be included in $landPage or $splashPage
|
||||
unset($svPasswd, $svEmail, $authorizedHosts, $validExtTypes, $currentUrlExt);
|
||||
// If $landPage file is present
|
||||
if (is_file(getcwd()."/$landPage")) {
|
||||
unset($serverName, $viewPort); // unset extra variables not to be included in $landpage
|
||||
include $landPage;
|
||||
exit();
|
||||
}
|
||||
// If $landPage file was not present, Set Splash Page output
|
||||
$splashPage = <<<EOT
|
||||
// Set Splash Page output
|
||||
$splashPage = "
|
||||
<!doctype html>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
$viewPort
|
||||
<title>● $serverName</title>
|
||||
<link rel='stylesheet' href='/pihole/blockingpage.css'>
|
||||
<link rel='shortcut icon' href='/admin/img/favicons/favicon.ico' type='image/x-icon'>
|
||||
<link rel='stylesheet' href='pihole/blockingpage.css'>
|
||||
<link rel='shortcut icon' href='admin/img/favicons/favicon.ico' type='image/x-icon'>
|
||||
</head>
|
||||
<body id='splashpage'>
|
||||
<div id="pihole_card">
|
||||
<img src='/admin/img/logo.svg' alt='Pi-hole logo' id="pihole_logo_splash" />
|
||||
<p>Pi-<strong>hole</strong>: Your black hole for Internet advertisements</p>
|
||||
<a href='/admin'>Did you mean to go to the admin panel?</a>
|
||||
</div>
|
||||
<img src='admin/img/logo.svg' alt='Pi-hole logo' width='256' height='377'>
|
||||
<br>
|
||||
<p>Pi-<strong>hole</strong>: Your black hole for Internet advertisements</p>
|
||||
<a href='/admin'>Did you mean to go to the admin panel?</a>
|
||||
</body>
|
||||
</html>
|
||||
EOT;
|
||||
exit($splashPage);
|
||||
";
|
||||
|
||||
// Set splash/landing page based off presence of $landPage
|
||||
$renderPage = is_file(getcwd()."/$landPage") ? include $landPage : "$splashPage";
|
||||
|
||||
// Unset variables so as to not be included in $landPage
|
||||
unset($serverName, $svPasswd, $svEmail, $authorizedHosts, $validExtTypes, $currentUrlExt, $viewPort);
|
||||
|
||||
// Render splash/landing page when directly browsing via IP or authorized hostname
|
||||
exit($renderPage);
|
||||
} elseif ($currentUrlExt === "js") {
|
||||
// Serve Pi-hole JavaScript for blocked domains requesting JS
|
||||
exit(setHeader("js").'var x = "Pi-hole: A black hole for Internet advertisements."');
|
||||
@@ -164,35 +161,13 @@ ini_set("default_socket_timeout", 3);
|
||||
function queryAds($serverName) {
|
||||
// Determine the time it takes while querying adlists
|
||||
$preQueryTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
|
||||
|
||||
// Determine which protocol should be used
|
||||
$protocol = "http";
|
||||
if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ||
|
||||
(isset($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] === 'https') ||
|
||||
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
|
||||
) {
|
||||
$protocol = "https";
|
||||
}
|
||||
|
||||
// Format the URL
|
||||
$queryAdsURL = sprintf(
|
||||
"%s://127.0.0.1:%s/admin/scripts/pi-hole/php/queryads.php?domain=%s&bp",
|
||||
$protocol,
|
||||
"http://127.0.0.1:%s/admin/scripts/pi-hole/php/queryads.php?domain=%s&bp",
|
||||
$_SERVER["SERVER_PORT"],
|
||||
$serverName
|
||||
);
|
||||
|
||||
// Request the file and receive the response
|
||||
$queryAdsFile = file($queryAdsURL, FILE_IGNORE_NEW_LINES);
|
||||
|
||||
// $queryAdsFile must be an array (to avoid PHP 8.0+ error)
|
||||
if (is_array($queryAdsFile)) {
|
||||
$queryAds = array_values(array_filter(preg_replace("/data:\s+/", "", $queryAdsFile)));
|
||||
} else {
|
||||
// if not an array, return an error message
|
||||
return array("0" => "error", "1" => "<br>(".gettype($queryAdsFile).")<br>".print_r($queryAdsFile, true));
|
||||
}
|
||||
|
||||
$queryAds = file($queryAdsURL, FILE_IGNORE_NEW_LINES);
|
||||
$queryAds = array_values(array_filter(preg_replace("/data:\s+/", "", $queryAds)));
|
||||
$queryTime = sprintf("%.0f", (microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]) - $preQueryTime);
|
||||
|
||||
// Exception Handling
|
||||
@@ -330,7 +305,7 @@ setHeader();
|
||||
</p>
|
||||
</div>
|
||||
<div class="aboutLink">
|
||||
<a class="linkPH" href="https://docs.pi-hole.net/"><?php //About PH ?></a>
|
||||
<a class="linkPH" href="https://github.com/pi-hole/pi-hole/wiki/What-is-Pi-hole%3F-A-simple-explanation"><?php //About PH ?></a>
|
||||
<?php if (!empty($svEmail)) echo '<a class="linkEmail" href="mailto:'.$svEmail.'"></a>'; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -20,6 +20,7 @@ server.modules = (
|
||||
"mod_accesslog",
|
||||
"mod_auth",
|
||||
"mod_expire",
|
||||
"mod_compress",
|
||||
"mod_redirect",
|
||||
"mod_setenv",
|
||||
"mod_rewrite"
|
||||
@@ -36,15 +37,30 @@ server.port = 80
|
||||
accesslog.filename = "/var/log/lighttpd/access.log"
|
||||
accesslog.format = "%{%s}t|%V|%r|%s|%b"
|
||||
|
||||
# Allow streaming response
|
||||
# reference: https://redmine.lighttpd.net/projects/lighttpd/wiki/Server_stream-response-bodyDetails
|
||||
server.stream-response-body = 1
|
||||
#ssl.read-ahead = "disable"
|
||||
|
||||
index-file.names = ( "index.php", "index.html", "index.lighttpd.html" )
|
||||
url.access-deny = ( "~", ".inc", ".md", ".yml", ".ini" )
|
||||
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
|
||||
|
||||
compress.cache-dir = "/var/cache/lighttpd/compress/"
|
||||
compress.filetype = (
|
||||
"application/json",
|
||||
"application/vnd.ms-fontobject",
|
||||
"application/xml",
|
||||
"font/eot",
|
||||
"font/opentype",
|
||||
"font/otf",
|
||||
"font/ttf",
|
||||
"image/bmp",
|
||||
"image/svg+xml",
|
||||
"image/vnd.microsoft.icon",
|
||||
"image/x-icon",
|
||||
"text/css",
|
||||
"text/html",
|
||||
"text/javascript",
|
||||
"text/plain",
|
||||
"text/xml"
|
||||
)
|
||||
|
||||
mimetype.assign = (
|
||||
".ico" => "image/x-icon",
|
||||
".jpeg" => "image/jpeg",
|
||||
@@ -65,10 +81,6 @@ mimetype.assign = (
|
||||
".woff2" => "font/woff2"
|
||||
)
|
||||
|
||||
# Add user chosen options held in external file
|
||||
# This uses include_shell instead of an include wildcard for compatibility
|
||||
include_shell "cat external.conf 2>/dev/null"
|
||||
|
||||
# default listening port for IPv6 falls back to the IPv4 port
|
||||
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
|
||||
|
||||
@@ -83,6 +95,11 @@ $HTTP["url"] =~ "^/admin/" {
|
||||
"X-Pi-hole" => "The Pi-hole Web interface is working!",
|
||||
"X-Frame-Options" => "DENY"
|
||||
)
|
||||
|
||||
$HTTP["url"] =~ "\.(eot|otf|tt[cf]|woff2?)$" {
|
||||
# Allow Block Page access to local fonts
|
||||
setenv.add-response-header = ( "Access-Control-Allow-Origin" => "*" )
|
||||
}
|
||||
}
|
||||
|
||||
# Block . files from being served, such as .git, .github, .gitignore
|
||||
@@ -90,12 +107,9 @@ $HTTP["url"] =~ "^/admin/\.(.*)" {
|
||||
url.access-deny = ("")
|
||||
}
|
||||
|
||||
# allow teleporter and API qr code iframe on settings page
|
||||
$HTTP["url"] =~ "/(teleporter|api_token)\.php$" {
|
||||
$HTTP["referer"] =~ "/admin/settings\.php" {
|
||||
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
|
||||
}
|
||||
}
|
||||
|
||||
# Default expire header
|
||||
expire.url = ( "" => "access plus 0 seconds" )
|
||||
|
||||
# Add user chosen options held in external file
|
||||
# This uses include_shell instead of an include wildcard for compatibility
|
||||
include_shell "cat external.conf 2>/dev/null"
|
||||
|
@@ -21,6 +21,7 @@ server.modules = (
|
||||
"mod_expire",
|
||||
"mod_fastcgi",
|
||||
"mod_accesslog",
|
||||
"mod_compress",
|
||||
"mod_redirect",
|
||||
"mod_setenv",
|
||||
"mod_rewrite"
|
||||
@@ -37,15 +38,30 @@ server.port = 80
|
||||
accesslog.filename = "/var/log/lighttpd/access.log"
|
||||
accesslog.format = "%{%s}t|%V|%r|%s|%b"
|
||||
|
||||
# Allow streaming response
|
||||
# reference: https://redmine.lighttpd.net/projects/lighttpd/wiki/Server_stream-response-bodyDetails
|
||||
server.stream-response-body = 1
|
||||
#ssl.read-ahead = "disable"
|
||||
|
||||
index-file.names = ( "index.php", "index.html", "index.lighttpd.html" )
|
||||
url.access-deny = ( "~", ".inc", ".md", ".yml", ".ini" )
|
||||
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
|
||||
|
||||
compress.cache-dir = "/var/cache/lighttpd/compress/"
|
||||
compress.filetype = (
|
||||
"application/json",
|
||||
"application/vnd.ms-fontobject",
|
||||
"application/xml",
|
||||
"font/eot",
|
||||
"font/opentype",
|
||||
"font/otf",
|
||||
"font/ttf",
|
||||
"image/bmp",
|
||||
"image/svg+xml",
|
||||
"image/vnd.microsoft.icon",
|
||||
"image/x-icon",
|
||||
"text/css",
|
||||
"text/html",
|
||||
"text/javascript",
|
||||
"text/plain",
|
||||
"text/xml"
|
||||
)
|
||||
|
||||
mimetype.assign = (
|
||||
".ico" => "image/x-icon",
|
||||
".jpeg" => "image/jpeg",
|
||||
@@ -66,10 +82,6 @@ mimetype.assign = (
|
||||
".woff2" => "font/woff2"
|
||||
)
|
||||
|
||||
# Add user chosen options held in external file
|
||||
# This uses include_shell instead of an include wildcard for compatibility
|
||||
include_shell "cat external.conf 2>/dev/null"
|
||||
|
||||
# default listening port for IPv6 falls back to the IPv4 port
|
||||
#include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
|
||||
#include_shell "/usr/share/lighttpd/create-mime.assign.pl"
|
||||
@@ -91,6 +103,11 @@ $HTTP["url"] =~ "^/admin/" {
|
||||
"X-Pi-hole" => "The Pi-hole Web interface is working!",
|
||||
"X-Frame-Options" => "DENY"
|
||||
)
|
||||
|
||||
$HTTP["url"] =~ "\.(eot|otf|tt[cf]|woff2?)$" {
|
||||
# Allow Block Page access to local fonts
|
||||
setenv.add-response-header = ( "Access-Control-Allow-Origin" => "*" )
|
||||
}
|
||||
}
|
||||
|
||||
# Block . files from being served, such as .git, .github, .gitignore
|
||||
@@ -98,12 +115,9 @@ $HTTP["url"] =~ "^/admin/\.(.*)" {
|
||||
url.access-deny = ("")
|
||||
}
|
||||
|
||||
# allow teleporter and API qr code iframe on settings page
|
||||
$HTTP["url"] =~ "/(teleporter|api_token)\.php$" {
|
||||
$HTTP["referer"] =~ "/admin/settings\.php" {
|
||||
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
|
||||
}
|
||||
}
|
||||
|
||||
# Default expire header
|
||||
expire.url = ( "" => "access plus 0 seconds" )
|
||||
|
||||
# Add user chosen options held in external file
|
||||
# This uses include_shell instead of an include wildcard for compatibility
|
||||
include_shell "cat external.conf 2>/dev/null"
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -11,9 +11,10 @@
|
||||
source "/opt/pihole/COL_TABLE"
|
||||
|
||||
while true; do
|
||||
read -rp " ${QST} Are you sure you would like to remove ${COL_WHITE}Pi-hole${COL_NC}? [y/N] " answer
|
||||
case ${answer} in
|
||||
read -rp " ${QST} Are you sure you would like to remove ${COL_WHITE}Pi-hole${COL_NC}? [y/N] " yn
|
||||
case ${yn} in
|
||||
[Yy]* ) break;;
|
||||
[Nn]* ) echo -e "${OVER} ${COL_LIGHT_GREEN}Uninstall has been canceled${COL_NC}"; exit 0;;
|
||||
* ) echo -e "${OVER} ${COL_LIGHT_GREEN}Uninstall has been canceled${COL_NC}"; exit 0;;
|
||||
esac
|
||||
done
|
||||
@@ -30,7 +31,7 @@ else
|
||||
else
|
||||
echo -e " ${CROSS} ${str}
|
||||
Script called with non-root privileges
|
||||
The Pi-hole requires elevated privileges to uninstall"
|
||||
The Pi-hole requires elevated privleges to uninstall"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -41,8 +42,8 @@ source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||
# setupVars set in basic-install.sh
|
||||
source "${setupVars}"
|
||||
|
||||
# package_manager_detect() sourced from basic-install.sh
|
||||
package_manager_detect
|
||||
# distro_check() sourced from basic-install.sh
|
||||
distro_check
|
||||
|
||||
# Install packages used by the Pi-hole
|
||||
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}")
|
||||
@@ -75,8 +76,8 @@ removeAndPurge() {
|
||||
for i in "${DEPS[@]}"; do
|
||||
if package_check "${i}" > /dev/null; then
|
||||
while true; do
|
||||
read -rp " ${QST} Do you wish to remove ${COL_WHITE}${i}${COL_NC} from your system? [Y/N] " answer
|
||||
case ${answer} in
|
||||
read -rp " ${QST} Do you wish to remove ${COL_WHITE}${i}${COL_NC} from your system? [Y/N] " yn
|
||||
case ${yn} in
|
||||
[Yy]* )
|
||||
echo -ne " ${INFO} Removing ${i}...";
|
||||
${SUDO} "${PKG_REMOVE[@]}" "${i}" &> /dev/null;
|
||||
@@ -112,7 +113,7 @@ removeNoPurge() {
|
||||
fi
|
||||
fi
|
||||
echo -e "${OVER} ${TICK} Removed Web Interface"
|
||||
|
||||
|
||||
# Attempt to preserve backwards compatibility with older versions
|
||||
# to guarantee no additional changes were made to /etc/crontab after
|
||||
# the installation of pihole, /etc/crontab.pihole should be permanently
|
||||
@@ -144,7 +145,6 @@ removeNoPurge() {
|
||||
|
||||
${SUDO} rm -f /etc/dnsmasq.d/adList.conf &> /dev/null
|
||||
${SUDO} rm -f /etc/dnsmasq.d/01-pihole.conf &> /dev/null
|
||||
${SUDO} rm -f /etc/dnsmasq.d/06-rfc6761.conf &> /dev/null
|
||||
${SUDO} rm -rf /var/log/*pihole* &> /dev/null
|
||||
${SUDO} rm -rf /etc/pihole/ &> /dev/null
|
||||
${SUDO} rm -rf /etc/.pihole/ &> /dev/null
|
||||
@@ -206,7 +206,11 @@ removeNoPurge() {
|
||||
}
|
||||
|
||||
######### SCRIPT ###########
|
||||
echo -e " ${INFO} Be sure to confirm if any dependencies should not be removed"
|
||||
if command -v vcgencmd &> /dev/null; then
|
||||
echo -e " ${INFO} All dependencies are safe to remove on Raspbian"
|
||||
else
|
||||
echo -e " ${INFO} Be sure to confirm if any dependencies should not be removed"
|
||||
fi
|
||||
while true; do
|
||||
echo -e " ${INFO} ${COL_YELLOW}The following dependencies may have been added by the Pi-hole install:"
|
||||
echo -n " "
|
||||
@@ -214,8 +218,8 @@ while true; do
|
||||
echo -n "${i} "
|
||||
done
|
||||
echo "${COL_NC}"
|
||||
read -rp " ${QST} Do you wish to go through each dependency for removal? (Choosing No will leave all dependencies installed) [Y/n] " answer
|
||||
case ${answer} in
|
||||
read -rp " ${QST} Do you wish to go through each dependency for removal? (Choosing No will leave all dependencies installed) [Y/n] " yn
|
||||
case ${yn} in
|
||||
[Yy]* ) removeAndPurge; break;;
|
||||
[Nn]* ) removeNoPurge; break;;
|
||||
* ) removeAndPurge; break;;
|
||||
|
484
gravity.sh
484
gravity.sh
@@ -15,6 +15,8 @@ export LC_ALL=C
|
||||
|
||||
coltable="/opt/pihole/COL_TABLE"
|
||||
source "${coltable}"
|
||||
regexconverter="/opt/pihole/wildcard_regex_converter.sh"
|
||||
source "${regexconverter}"
|
||||
# shellcheck disable=SC1091
|
||||
source "/etc/.pihole/advanced/Scripts/database_migration/gravity-db.sh"
|
||||
|
||||
@@ -33,11 +35,11 @@ localList="${piholeDir}/local.list"
|
||||
VPNList="/etc/openvpn/ipp.txt"
|
||||
|
||||
piholeGitDir="/etc/.pihole"
|
||||
gravityDBfile_default="${piholeDir}/gravity.db"
|
||||
# GRAVITYDB may be overwritten by source pihole-FTL.conf below
|
||||
GRAVITYDB="${gravityDBfile_default}"
|
||||
gravityDBfile="${piholeDir}/gravity.db"
|
||||
gravityTEMPfile="${piholeDir}/gravity_temp.db"
|
||||
gravityDBschema="${piholeGitDir}/advanced/Templates/gravity.db.sql"
|
||||
gravityDBcopy="${piholeGitDir}/advanced/Templates/gravity_copy.sql"
|
||||
optimize_database=false
|
||||
|
||||
domainsExtension="domains"
|
||||
|
||||
@@ -45,6 +47,16 @@ domainsExtension="domains"
|
||||
setupVars="${piholeDir}/setupVars.conf"
|
||||
if [[ -f "${setupVars}" ]];then
|
||||
source "${setupVars}"
|
||||
|
||||
# Remove CIDR mask from IPv4/6 addresses
|
||||
IPV4_ADDRESS="${IPV4_ADDRESS%/*}"
|
||||
IPV6_ADDRESS="${IPV6_ADDRESS%/*}"
|
||||
|
||||
# Determine if IPv4/6 addresses exist
|
||||
if [[ -z "${IPV4_ADDRESS}" ]] && [[ -z "${IPV6_ADDRESS}" ]]; then
|
||||
echo -e " ${COL_LIGHT_RED}No IP addresses found! Please run 'pihole -r' to reconfigure${COL_NC}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo -e " ${COL_LIGHT_RED}Installation Failure: ${setupVars} does not exist! ${COL_NC}
|
||||
Please run 'pihole -r', and choose the 'reconfigure' option to fix."
|
||||
@@ -57,13 +69,6 @@ if [[ -f "${pihole_FTL}" ]]; then
|
||||
source "${pihole_FTL}"
|
||||
fi
|
||||
|
||||
# Set this only after sourcing pihole-FTL.conf as the gravity database path may
|
||||
# have changed
|
||||
gravityDBfile="${GRAVITYDB}"
|
||||
gravityTEMPfile="${GRAVITYDB}_temp"
|
||||
gravityDIR="$(dirname -- "${gravityDBfile}")"
|
||||
gravityOLDfile="${gravityDIR}/gravity_old.db"
|
||||
|
||||
if [[ -z "${BLOCKINGMODE}" ]] ; then
|
||||
BLOCKINGMODE="NULL"
|
||||
fi
|
||||
@@ -73,24 +78,19 @@ if [[ -r "${piholeDir}/pihole.conf" ]]; then
|
||||
echo -e " ${COL_LIGHT_RED}Ignoring overrides specified within pihole.conf! ${COL_NC}"
|
||||
fi
|
||||
|
||||
# Generate new SQLite3 file from schema template
|
||||
# Generate new sqlite3 file from schema template
|
||||
generate_gravity_database() {
|
||||
if ! pihole-FTL sqlite3 "${gravityDBfile}" < "${gravityDBschema}"; then
|
||||
echo -e " ${CROSS} Unable to create ${gravityDBfile}"
|
||||
return 1
|
||||
fi
|
||||
chown pihole:pihole "${gravityDBfile}"
|
||||
chmod g+w "${piholeDir}" "${gravityDBfile}"
|
||||
sqlite3 "${1}" < "${gravityDBschema}"
|
||||
}
|
||||
|
||||
# Copy data from old to new database file and swap them
|
||||
gravity_swap_databases() {
|
||||
local str copyGravity oldAvail
|
||||
local str
|
||||
str="Building tree"
|
||||
echo -ne " ${INFO} ${str}..."
|
||||
|
||||
# The index is intentionally not UNIQUE as poor quality adlists may contain domains more than once
|
||||
output=$( { pihole-FTL sqlite3 "${gravityTEMPfile}" "CREATE INDEX idx_gravity ON gravity (domain, adlist_id);"; } 2>&1 )
|
||||
# The index is intentionally not UNIQUE as prro quality adlists may contain domains more than once
|
||||
output=$( { sqlite3 "${gravityTEMPfile}" "CREATE INDEX idx_gravity ON gravity (domain, adlist_id);"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
@@ -102,31 +102,23 @@ gravity_swap_databases() {
|
||||
str="Swapping databases"
|
||||
echo -ne " ${INFO} ${str}..."
|
||||
|
||||
# Swap databases and remove or conditionally rename old database
|
||||
# Number of available blocks on disk
|
||||
availableBlocks=$(stat -f --format "%a" "${gravityDIR}")
|
||||
# Number of blocks, used by gravity.db
|
||||
gravityBlocks=$(stat --format "%b" ${gravityDBfile})
|
||||
# Only keep the old database if available disk space is at least twice the size of the existing gravity.db.
|
||||
# Better be safe than sorry...
|
||||
oldAvail=false
|
||||
if [ "${availableBlocks}" -gt "$((gravityBlocks * 2))" ] && [ -f "${gravityDBfile}" ]; then
|
||||
oldAvail=true
|
||||
mv "${gravityDBfile}" "${gravityOLDfile}"
|
||||
else
|
||||
rm "${gravityDBfile}"
|
||||
output=$( { sqlite3 "${gravityTEMPfile}" < "${gravityDBcopy}"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
echo -e "\\n ${CROSS} Unable to copy data from ${gravityDBfile} to ${gravityTEMPfile}\\n ${output}"
|
||||
return 1
|
||||
fi
|
||||
mv "${gravityTEMPfile}" "${gravityDBfile}"
|
||||
echo -e "${OVER} ${TICK} ${str}"
|
||||
|
||||
if $oldAvail; then
|
||||
echo -e " ${TICK} The old database remains available."
|
||||
fi
|
||||
# Swap databases and remove old database
|
||||
rm "${gravityDBfile}"
|
||||
mv "${gravityTEMPfile}" "${gravityDBfile}"
|
||||
}
|
||||
|
||||
# Update timestamp when the gravity table was last updated successfully
|
||||
update_gravity_timestamp() {
|
||||
output=$( { printf ".timeout 30000\\nINSERT OR REPLACE INTO info (property,value) values ('updated',cast(strftime('%%s', 'now') as int));" | pihole-FTL sqlite3 "${gravityDBfile}"; } 2>&1 )
|
||||
output=$( { printf ".timeout 30000\\nINSERT OR REPLACE INTO info (property,value) values ('updated',cast(strftime('%%s', 'now') as int));" | sqlite3 "${gravityDBfile}"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
@@ -167,7 +159,7 @@ database_table_from_file() {
|
||||
|
||||
# Get MAX(id) from domainlist when INSERTing into this table
|
||||
if [[ "${table}" == "domainlist" ]]; then
|
||||
rowid="$(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT MAX(id) FROM domainlist;")"
|
||||
rowid="$(sqlite3 "${gravityDBfile}" "SELECT MAX(id) FROM domainlist;")"
|
||||
if [[ -z "$rowid" ]]; then
|
||||
rowid=0
|
||||
fi
|
||||
@@ -185,7 +177,7 @@ database_table_from_file() {
|
||||
echo "${rowid},\"${domain}\",${timestamp}" >> "${tmpFile}"
|
||||
elif [[ "${table}" == "adlist" ]]; then
|
||||
# Adlist table format
|
||||
echo "${rowid},\"${domain}\",1,${timestamp},${timestamp},\"Migrated from ${source}\",,0,0,0" >> "${tmpFile}"
|
||||
echo "${rowid},\"${domain}\",1,${timestamp},${timestamp},\"Migrated from ${source}\"" >> "${tmpFile}"
|
||||
else
|
||||
# White-, black-, and regexlist table format
|
||||
echo "${rowid},${type},\"${domain}\",1,${timestamp},${timestamp},\"Migrated from ${source}\"" >> "${tmpFile}"
|
||||
@@ -197,7 +189,7 @@ database_table_from_file() {
|
||||
# Store domains in database table specified by ${table}
|
||||
# Use printf as .mode and .import need to be on separate lines
|
||||
# see https://unix.stackexchange.com/a/445615/83260
|
||||
output=$( { printf ".timeout 30000\\n.mode csv\\n.import \"%s\" %s\\n" "${tmpFile}" "${table}" | pihole-FTL sqlite3 "${gravityDBfile}"; } 2>&1 )
|
||||
output=$( { printf ".timeout 30000\\n.mode csv\\n.import \"%s\" %s\\n" "${tmpFile}" "${table}" | sqlite3 "${gravityDBfile}"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
@@ -208,76 +200,20 @@ database_table_from_file() {
|
||||
# Move source file to backup directory, create directory if not existing
|
||||
mkdir -p "${backup_path}"
|
||||
mv "${source}" "${backup_file}" 2> /dev/null || \
|
||||
echo -e " ${CROSS} Unable to backup ${source} to ${backup_path}"
|
||||
echo -e " ${CROSS} Unable to backup ${source} to ${backup_path}"
|
||||
|
||||
# Delete tmpFile
|
||||
rm "${tmpFile}" > /dev/null 2>&1 || \
|
||||
echo -e " ${CROSS} Unable to remove ${tmpFile}"
|
||||
}
|
||||
|
||||
# Update timestamp of last update of this list. We store this in the "old" database as all values in the new database will later be overwritten
|
||||
database_adlist_updated() {
|
||||
output=$( { printf ".timeout 30000\\nUPDATE adlist SET date_updated = (cast(strftime('%%s', 'now') as int)) WHERE id = %i;\\n" "${1}" | pihole-FTL sqlite3 "${gravityDBfile}"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
echo -e "\\n ${CROSS} Unable to update timestamp of adlist with ID ${1} in database ${gravityDBfile}\\n ${output}"
|
||||
gravity_Cleanup "error"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if a column with name ${2} exists in gravity table with name ${1}
|
||||
gravity_column_exists() {
|
||||
output=$( { printf ".timeout 30000\\nSELECT EXISTS(SELECT * FROM pragma_table_info('%s') WHERE name='%s');\\n" "${1}" "${2}" | pihole-FTL sqlite3 "${gravityDBfile}"; } 2>&1 )
|
||||
if [[ "${output}" == "1" ]]; then
|
||||
return 0 # Bash 0 is success
|
||||
fi
|
||||
|
||||
return 1 # Bash non-0 is failure
|
||||
}
|
||||
|
||||
# Update number of domain on this list. We store this in the "old" database as all values in the new database will later be overwritten
|
||||
database_adlist_number() {
|
||||
# Only try to set number of domains when this field exists in the gravity database
|
||||
if ! gravity_column_exists "adlist" "number"; then
|
||||
return;
|
||||
fi
|
||||
|
||||
output=$( { printf ".timeout 30000\\nUPDATE adlist SET number = %i, invalid_domains = %i WHERE id = %i;\\n" "${num_source_lines}" "${num_invalid}" "${1}" | pihole-FTL sqlite3 "${gravityDBfile}"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
echo -e "\\n ${CROSS} Unable to update number of domains in adlist with ID ${1} in database ${gravityDBfile}\\n ${output}"
|
||||
gravity_Cleanup "error"
|
||||
fi
|
||||
}
|
||||
|
||||
# Update status of this list. We store this in the "old" database as all values in the new database will later be overwritten
|
||||
database_adlist_status() {
|
||||
# Only try to set the status when this field exists in the gravity database
|
||||
if ! gravity_column_exists "adlist" "status"; then
|
||||
return;
|
||||
fi
|
||||
|
||||
output=$( { printf ".timeout 30000\\nUPDATE adlist SET status = %i WHERE id = %i;\\n" "${2}" "${1}" | pihole-FTL sqlite3 "${gravityDBfile}"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
echo -e "\\n ${CROSS} Unable to update status of adlist with ID ${1} in database ${gravityDBfile}\\n ${output}"
|
||||
gravity_Cleanup "error"
|
||||
fi
|
||||
}
|
||||
|
||||
# Migrate pre-v5.0 list files to database-based Pi-hole versions
|
||||
migrate_to_database() {
|
||||
# Create database file only if not present
|
||||
if [ ! -e "${gravityDBfile}" ]; then
|
||||
# Create new database file - note that this will be created in version 1
|
||||
echo -e " ${INFO} Creating new gravity database"
|
||||
if ! generate_gravity_database; then
|
||||
echo -e " ${CROSS} Error creating new gravity database. Please contact support."
|
||||
return 1
|
||||
fi
|
||||
generate_gravity_database "${gravityDBfile}"
|
||||
|
||||
# Check if gravity database needs to be updated
|
||||
upgrade_gravityDB "${gravityDBfile}" "${piholeDir}"
|
||||
@@ -371,14 +307,10 @@ gravity_CheckDNSResolutionAvailable() {
|
||||
gravity_DownloadBlocklists() {
|
||||
echo -e " ${INFO} ${COL_BOLD}Neutrino emissions detected${COL_NC}..."
|
||||
|
||||
if [[ "${gravityDBfile}" != "${gravityDBfile_default}" ]]; then
|
||||
echo -e " ${INFO} Storing gravity database in ${COL_BOLD}${gravityDBfile}${COL_NC}"
|
||||
fi
|
||||
|
||||
# Retrieve source URLs from gravity database
|
||||
# We source only enabled adlists, SQLite3 stores boolean values as 0 (false) or 1 (true)
|
||||
mapfile -t sources <<< "$(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT address FROM vw_adlist;" 2> /dev/null)"
|
||||
mapfile -t sourceIDs <<< "$(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT id FROM vw_adlist;" 2> /dev/null)"
|
||||
# We source only enabled adlists, sqlite3 stores boolean values as 0 (false) or 1 (true)
|
||||
mapfile -t sources <<< "$(sqlite3 "${gravityDBfile}" "SELECT address FROM vw_adlist;" 2> /dev/null)"
|
||||
mapfile -t sourceIDs <<< "$(sqlite3 "${gravityDBfile}" "SELECT id FROM vw_adlist;" 2> /dev/null)"
|
||||
|
||||
# Parse source domains from $sources
|
||||
mapfile -t sourceDomains <<< "$(
|
||||
@@ -392,22 +324,24 @@ gravity_DownloadBlocklists() {
|
||||
)"
|
||||
|
||||
local str="Pulling blocklist source list into range"
|
||||
echo -e "${OVER} ${TICK} ${str}"
|
||||
|
||||
if [[ -z "${sources[*]}" ]] || [[ -z "${sourceDomains[*]}" ]]; then
|
||||
if [[ -n "${sources[*]}" ]] && [[ -n "${sourceDomains[*]}" ]]; then
|
||||
echo -e "${OVER} ${TICK} ${str}"
|
||||
else
|
||||
echo -e "${OVER} ${CROSS} ${str}"
|
||||
echo -e " ${INFO} No source list found, or it is empty"
|
||||
echo ""
|
||||
unset sources
|
||||
return 1
|
||||
fi
|
||||
|
||||
local url domain agent cmd_ext str target compression
|
||||
local url domain agent cmd_ext str target
|
||||
echo ""
|
||||
|
||||
# Prepare new gravity database
|
||||
str="Preparing new gravity database"
|
||||
echo -ne " ${INFO} ${str}..."
|
||||
rm "${gravityTEMPfile}" > /dev/null 2>&1
|
||||
output=$( { pihole-FTL sqlite3 "${gravityTEMPfile}" < "${gravityDBschema}"; } 2>&1 )
|
||||
output=$( { sqlite3 "${gravityTEMPfile}" < "${gravityDBschema}"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
@@ -419,24 +353,13 @@ gravity_DownloadBlocklists() {
|
||||
|
||||
target="$(mktemp -p "/tmp" --suffix=".gravity")"
|
||||
|
||||
# Use compression to reduce the amount of data that is transferred
|
||||
# between the Pi-hole and the ad list provider. Use this feature
|
||||
# only if it is supported by the locally available version of curl
|
||||
if curl -V | grep -q "Features:.* libz"; then
|
||||
compression="--compressed"
|
||||
echo -e " ${INFO} Using libz compression\n"
|
||||
else
|
||||
compression=""
|
||||
echo -e " ${INFO} Libz compression not available\n"
|
||||
fi
|
||||
# Loop through $sources and download each one
|
||||
for ((i = 0; i < "${#sources[@]}"; i++)); do
|
||||
url="${sources[$i]}"
|
||||
domain="${sourceDomains[$i]}"
|
||||
id="${sourceIDs[$i]}"
|
||||
|
||||
# Save the file as list.#.domain
|
||||
saveLocation="${piholeDir}/list.${id}.${domain}.${domainsExtension}"
|
||||
saveLocation="${piholeDir}/list.${i}.${domain}.${domainsExtension}"
|
||||
activeDomains[$i]="${saveLocation}"
|
||||
|
||||
# Default user-agent (for Cloudflare's Browser Integrity Check: https://support.cloudflare.com/hc/en-us/articles/200170086-What-does-the-Browser-Integrity-Check-do-)
|
||||
@@ -449,44 +372,20 @@ gravity_DownloadBlocklists() {
|
||||
esac
|
||||
|
||||
echo -e " ${INFO} Target: ${url}"
|
||||
local regex check_url
|
||||
local regex
|
||||
# Check for characters NOT allowed in URLs
|
||||
regex="[^a-zA-Z0-9:/?&%=~._()-;]"
|
||||
|
||||
# this will remove first @ that is after schema and before domain
|
||||
# \1 is optional schema, \2 is userinfo
|
||||
check_url="$( sed -re 's#([^:/]*://)?([^/]+)@#\1\2#' <<< "$url" )"
|
||||
|
||||
if [[ "${check_url}" =~ ${regex} ]]; then
|
||||
echo -e " ${CROSS} Invalid Target"
|
||||
if [[ "${url}" =~ ${regex} ]]; then
|
||||
echo -e " ${CROSS} Invalid Target"
|
||||
else
|
||||
gravity_DownloadBlocklistFromUrl "${url}" "${cmd_ext}" "${agent}" "${sourceIDs[$i]}" "${saveLocation}" "${target}" "${compression}"
|
||||
gravity_DownloadBlocklistFromUrl "${url}" "${cmd_ext}" "${agent}" "${sourceIDs[$i]}" "${saveLocation}" "${target}"
|
||||
fi
|
||||
echo ""
|
||||
done
|
||||
|
||||
str="Creating new gravity databases"
|
||||
echo -ne " ${INFO} ${str}..."
|
||||
|
||||
# Gravity copying SQL script
|
||||
copyGravity="$(cat "${gravityDBcopy}")"
|
||||
if [[ "${gravityDBfile}" != "${gravityDBfile_default}" ]]; then
|
||||
# Replace default gravity script location by custom location
|
||||
copyGravity="${copyGravity//"${gravityDBfile_default}"/"${gravityDBfile}"}"
|
||||
fi
|
||||
|
||||
output=$( { pihole-FTL sqlite3 "${gravityTEMPfile}" <<< "${copyGravity}"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
echo -e "\\n ${CROSS} Unable to copy data from ${gravityDBfile} to ${gravityTEMPfile}\\n ${output}"
|
||||
return 1
|
||||
fi
|
||||
echo -e "${OVER} ${TICK} ${str}"
|
||||
|
||||
str="Storing downloaded domains in new gravity database"
|
||||
echo -ne " ${INFO} ${str}..."
|
||||
output=$( { printf ".timeout 30000\\n.mode csv\\n.import \"%s\" gravity\\n" "${target}" | pihole-FTL sqlite3 "${gravityTEMPfile}"; } 2>&1 )
|
||||
output=$( { printf ".timeout 30000\\n.mode csv\\n.import \"%s\" gravity\\n" "${target}" | sqlite3 "${gravityTEMPfile}"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
@@ -518,10 +417,7 @@ gravity_DownloadBlocklists() {
|
||||
gravity_Blackbody=true
|
||||
}
|
||||
|
||||
# num_target_lines does increase for every correctly added domain in pareseList()
|
||||
num_target_lines=0
|
||||
num_source_lines=0
|
||||
num_invalid=0
|
||||
total_num=0
|
||||
parseList() {
|
||||
local adlistID="${1}" src="${2}" target="${3}" incorrect_lines
|
||||
# This sed does the following things:
|
||||
@@ -532,20 +428,18 @@ parseList() {
|
||||
# Find (up to) five domains containing invalid characters (see above)
|
||||
incorrect_lines="$(sed -e "/[^a-zA-Z0-9.\_-]/!d" "${src}" | head -n 5)"
|
||||
|
||||
local num_target_lines_new num_correct_lines
|
||||
local num_lines num_target_lines num_correct_lines num_invalid
|
||||
# Get number of lines in source file
|
||||
num_source_lines="$(grep -c "^" "${src}")"
|
||||
# Get the new number of lines in destination file
|
||||
num_target_lines_new="$(grep -c "^" "${target}")"
|
||||
# Number of new correctly added lines
|
||||
num_correct_lines="$(( num_target_lines_new-num_target_lines ))"
|
||||
# Upate number of lines in target file
|
||||
num_target_lines="$num_target_lines_new"
|
||||
num_invalid="$(( num_source_lines-num_correct_lines ))"
|
||||
num_lines="$(grep -c "^" "${src}")"
|
||||
# Get number of lines in destination file
|
||||
num_target_lines="$(grep -c "^" "${target}")"
|
||||
num_correct_lines="$(( num_target_lines-total_num ))"
|
||||
total_num="$num_target_lines"
|
||||
num_invalid="$(( num_lines-num_correct_lines ))"
|
||||
if [[ "${num_invalid}" -eq 0 ]]; then
|
||||
echo " ${INFO} Analyzed ${num_source_lines} domains"
|
||||
echo " ${INFO} Received ${num_lines} domains"
|
||||
else
|
||||
echo " ${INFO} Analyzed ${num_source_lines} domains, ${num_invalid} domains invalid!"
|
||||
echo " ${INFO} Received ${num_lines} domains, ${num_invalid} domains invalid!"
|
||||
fi
|
||||
|
||||
# Display sample of invalid lines if we found some
|
||||
@@ -556,34 +450,11 @@ parseList() {
|
||||
done <<< "${incorrect_lines}"
|
||||
fi
|
||||
}
|
||||
compareLists() {
|
||||
local adlistID="${1}" target="${2}"
|
||||
|
||||
# Verify checksum when an older checksum exists
|
||||
if [[ -s "${target}.sha1" ]]; then
|
||||
if ! sha1sum --check --status --strict "${target}.sha1"; then
|
||||
# The list changed upstream, we need to update the checksum
|
||||
sha1sum "${target}" > "${target}.sha1"
|
||||
echo " ${INFO} List has been updated"
|
||||
database_adlist_status "${adlistID}" "1"
|
||||
database_adlist_updated "${adlistID}"
|
||||
else
|
||||
echo " ${INFO} List stayed unchanged"
|
||||
database_adlist_status "${adlistID}" "2"
|
||||
fi
|
||||
else
|
||||
# No checksum available, create one for comparing on the next run
|
||||
sha1sum "${target}" > "${target}.sha1"
|
||||
# We assume here it was changed upstream
|
||||
database_adlist_status "${adlistID}" "1"
|
||||
database_adlist_updated "${adlistID}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Download specified URL and perform checks on HTTP status and file content
|
||||
gravity_DownloadBlocklistFromUrl() {
|
||||
local url="${1}" cmd_ext="${2}" agent="${3}" adlistID="${4}" saveLocation="${5}" target="${6}" compression="${7}"
|
||||
local heisenbergCompensator="" patternBuffer str httpCode success="" ip
|
||||
local url="${1}" cmd_ext="${2}" agent="${3}" adlistID="${4}" saveLocation="${5}" target="${6}"
|
||||
local heisenbergCompensator="" patternBuffer str httpCode success=""
|
||||
|
||||
# Create temp file to store content on disk instead of RAM
|
||||
patternBuffer=$(mktemp -p "/tmp" --suffix=".phgpb")
|
||||
@@ -601,32 +472,25 @@ gravity_DownloadBlocklistFromUrl() {
|
||||
blocked=false
|
||||
case $BLOCKINGMODE in
|
||||
"IP-NODATA-AAAA"|"IP")
|
||||
# Get IP address of this domain
|
||||
ip="$(dig "${domain}" +short)"
|
||||
# Check if this IP matches any IP of the system
|
||||
if [[ -n "${ip}" && $(grep -Ec "inet(|6) ${ip}" <<< "$(ip a)") -gt 0 ]]; then
|
||||
blocked=true
|
||||
fi;;
|
||||
if [[ $(dig "${domain}" +short | grep "${IPV4_ADDRESS}" -c) -ge 1 ]]; then
|
||||
blocked=true
|
||||
fi;;
|
||||
"NXDOMAIN")
|
||||
if [[ $(dig "${domain}" | grep "NXDOMAIN" -c) -ge 1 ]]; then
|
||||
blocked=true
|
||||
fi;;
|
||||
"NODATA")
|
||||
if [[ $(dig "${domain}" | grep "NOERROR" -c) -ge 1 ]] && [[ -z $(dig +short "${domain}") ]]; then
|
||||
blocked=true
|
||||
fi;;
|
||||
if [[ $(dig "${domain}" | grep "NXDOMAIN" -c) -ge 1 ]]; then
|
||||
blocked=true
|
||||
fi;;
|
||||
"NULL"|*)
|
||||
if [[ $(dig "${domain}" +short | grep "0.0.0.0" -c) -ge 1 ]]; then
|
||||
blocked=true
|
||||
fi;;
|
||||
esac
|
||||
if [[ $(dig "${domain}" +short | grep "0.0.0.0" -c) -ge 1 ]]; then
|
||||
blocked=true
|
||||
fi;;
|
||||
esac
|
||||
|
||||
if [[ "${blocked}" == true ]]; then
|
||||
printf -v ip_addr "%s" "${PIHOLE_DNS_1%#*}"
|
||||
if [[ ${PIHOLE_DNS_1} != *"#"* ]]; then
|
||||
port=53
|
||||
port=53
|
||||
else
|
||||
printf -v port "%s" "${PIHOLE_DNS_1#*#}"
|
||||
printf -v port "%s" "${PIHOLE_DNS_1#*#}"
|
||||
fi
|
||||
ip=$(dig "@${ip_addr}" -p "${port}" +short "${domain}" | tail -1)
|
||||
if [[ $(echo "${url}" | awk -F '://' '{print $1}') = "https" ]]; then
|
||||
@@ -638,18 +502,17 @@ gravity_DownloadBlocklistFromUrl() {
|
||||
echo -ne " ${INFO} ${str} Pending..."
|
||||
cmd_ext="--resolve $domain:$port:$ip $cmd_ext"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
httpCode=$(curl -s -L ${compression} ${cmd_ext} ${heisenbergCompensator} -w "%{http_code}" -A "${agent}" "${url}" -o "${patternBuffer}" 2> /dev/null)
|
||||
httpCode=$(curl -s -L ${cmd_ext} ${heisenbergCompensator} -w "%{http_code}" -A "${agent}" "${url}" -o "${patternBuffer}" 2> /dev/null)
|
||||
|
||||
case $url in
|
||||
# Did we "download" a local file?
|
||||
"file"*)
|
||||
if [[ -s "${patternBuffer}" ]]; then
|
||||
echo -e "${OVER} ${TICK} ${str} Retrieval successful"; success=true
|
||||
else
|
||||
echo -e "${OVER} ${CROSS} ${str} Not found / empty list"
|
||||
fi;;
|
||||
if [[ -s "${patternBuffer}" ]]; then
|
||||
echo -e "${OVER} ${TICK} ${str} Retrieval successful"; success=true
|
||||
else
|
||||
echo -e "${OVER} ${CROSS} ${str} Not found / empty list"
|
||||
fi;;
|
||||
# Did we "download" a remote file?
|
||||
*)
|
||||
# Determine "Status:" output based on HTTP response
|
||||
@@ -669,49 +532,29 @@ gravity_DownloadBlocklistFromUrl() {
|
||||
esac;;
|
||||
esac
|
||||
|
||||
local done="false"
|
||||
# Determine if the blocklist was downloaded and saved correctly
|
||||
if [[ "${success}" == true ]]; then
|
||||
if [[ "${httpCode}" == "304" ]]; then
|
||||
# Add domains to database table file
|
||||
parseList "${adlistID}" "${saveLocation}" "${target}"
|
||||
database_adlist_status "${adlistID}" "2"
|
||||
database_adlist_number "${adlistID}"
|
||||
done="true"
|
||||
# Check if $patternbuffer is a non-zero length file
|
||||
elif [[ -s "${patternBuffer}" ]]; then
|
||||
# Determine if blocklist is non-standard and parse as appropriate
|
||||
gravity_ParseFileIntoDomains "${patternBuffer}" "${saveLocation}"
|
||||
# Add domains to database table file
|
||||
parseList "${adlistID}" "${saveLocation}" "${target}"
|
||||
# Compare lists, are they identical?
|
||||
compareLists "${adlistID}" "${saveLocation}"
|
||||
# Update gravity database table (status and updated timestamp are set in
|
||||
# compareLists)
|
||||
database_adlist_number "${adlistID}"
|
||||
done="true"
|
||||
else
|
||||
# Fall back to previously cached list if $patternBuffer is empty
|
||||
echo -e " ${INFO} Received empty file"
|
||||
echo -e " ${INFO} Received empty file: ${COL_LIGHT_GREEN}using previously cached list${COL_NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Do we need to fall back to a cached list (if available)?
|
||||
if [[ "${done}" != "true" ]]; then
|
||||
else
|
||||
# Determine if cached list has read permission
|
||||
if [[ -r "${saveLocation}" ]]; then
|
||||
echo -e " ${CROSS} List download failed: ${COL_LIGHT_GREEN}using previously cached list${COL_NC}"
|
||||
# Add domains to database table file
|
||||
parseList "${adlistID}" "${saveLocation}" "${target}"
|
||||
database_adlist_number "${adlistID}"
|
||||
database_adlist_status "${adlistID}" "3"
|
||||
else
|
||||
echo -e " ${CROSS} List download failed: ${COL_LIGHT_RED}no cached list available${COL_NC}"
|
||||
# Manually reset these two numbers because we do not call parseList here
|
||||
num_source_lines=0
|
||||
num_invalid=0
|
||||
database_adlist_number "${adlistID}"
|
||||
database_adlist_status "${adlistID}" "4"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -723,7 +566,7 @@ gravity_ParseFileIntoDomains() {
|
||||
# Determine if we are parsing a consolidated list
|
||||
#if [[ "${source}" == "${piholeDir}/${matterAndLight}" ]]; then
|
||||
# Remove comments and print only the domain name
|
||||
# Most of the lists downloaded are already in hosts file format but the spacing/formatting is not contiguous
|
||||
# Most of the lists downloaded are already in hosts file format but the spacing/formating is not contiguous
|
||||
# This helps with that and makes it easier to read
|
||||
# It also helps with debugging so each stage of the script can be researched more in depth
|
||||
# 1) Remove carriage returns
|
||||
@@ -791,12 +634,12 @@ gravity_Table_Count() {
|
||||
local table="${1}"
|
||||
local str="${2}"
|
||||
local num
|
||||
num="$(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT COUNT(*) FROM ${table};")"
|
||||
num="$(sqlite3 "${gravityDBfile}" "SELECT COUNT(*) FROM ${table};")"
|
||||
if [[ "${table}" == "vw_gravity" ]]; then
|
||||
local unique
|
||||
unique="$(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT COUNT(DISTINCT domain) FROM ${table};")"
|
||||
unique="$(sqlite3 "${gravityDBfile}" "SELECT COUNT(DISTINCT domain) FROM ${table};")"
|
||||
echo -e " ${INFO} Number of ${str}: ${num} (${COL_BOLD}${unique} unique domains${COL_NC})"
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "INSERT OR REPLACE INTO info (property,value) VALUES ('gravity_count',${unique});"
|
||||
sqlite3 "${gravityDBfile}" "INSERT OR REPLACE INTO info (property,value) VALUES ('gravity_count',${unique});"
|
||||
else
|
||||
echo -e " ${INFO} Number of ${str}: ${num}"
|
||||
fi
|
||||
@@ -811,12 +654,43 @@ gravity_ShowCount() {
|
||||
gravity_Table_Count "vw_regex_whitelist" "regex whitelist filters"
|
||||
}
|
||||
|
||||
# Parse list of domains into hosts format
|
||||
gravity_ParseDomainsIntoHosts() {
|
||||
awk -v ipv4="$IPV4_ADDRESS" -v ipv6="$IPV6_ADDRESS" '{
|
||||
# Remove windows CR line endings
|
||||
sub(/\r$/, "")
|
||||
# Parse each line as "ipaddr domain"
|
||||
if(ipv6 && ipv4) {
|
||||
print ipv4" "$0"\n"ipv6" "$0
|
||||
} else if(!ipv6) {
|
||||
print ipv4" "$0
|
||||
} else {
|
||||
print ipv6" "$0
|
||||
}
|
||||
}' >> "${2}" < "${1}"
|
||||
}
|
||||
|
||||
# Create "localhost" entries into hosts format
|
||||
gravity_generateLocalList() {
|
||||
local hostname
|
||||
|
||||
if [[ -s "/etc/hostname" ]]; then
|
||||
hostname=$(< "/etc/hostname")
|
||||
elif command -v hostname &> /dev/null; then
|
||||
hostname=$(hostname -f)
|
||||
else
|
||||
echo -e " ${CROSS} Unable to determine fully qualified domain name of host"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${hostname}\\npi.hole" > "${localList}.tmp"
|
||||
|
||||
# Empty $localList if it already exists, otherwise, create it
|
||||
echo "### Do not modify this file, it will be overwritten by pihole -g" > "${localList}"
|
||||
: > "${localList}"
|
||||
chmod 644 "${localList}"
|
||||
|
||||
gravity_ParseDomainsIntoHosts "${localList}.tmp" "${localList}"
|
||||
|
||||
# Add additional LAN hosts provided by OpenVPN (if available)
|
||||
if [[ -f "${VPNList}" ]]; then
|
||||
awk -F, '{printf $2"\t"$1".vpn\n"}' "${VPNList}" >> "${localList}"
|
||||
@@ -828,6 +702,21 @@ gravity_Trap() {
|
||||
trap '{ echo -e "\\n\\n ${INFO} ${COL_LIGHT_RED}User-abort detected${COL_NC}"; gravity_Cleanup "error"; }' INT
|
||||
}
|
||||
|
||||
gravity_Optimize() {
|
||||
str="Optimizing domains database"
|
||||
echo -ne " ${INFO} ${str}..."
|
||||
# Run VACUUM command on database to optimize it
|
||||
output=$( { sqlite3 "${gravityDBfile}" "VACUUM;"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
echo -e "\\n ${CROSS} Unable to optimize gravity database ${gravityDBfile}\\n ${output}"
|
||||
error="error"
|
||||
else
|
||||
echo -e "${OVER} ${TICK} ${str}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Clean up after Gravity upon exit or cancellation
|
||||
gravity_Cleanup() {
|
||||
local error="${1:-}"
|
||||
@@ -867,49 +756,6 @@ gravity_Cleanup() {
|
||||
fi
|
||||
}
|
||||
|
||||
database_recovery() {
|
||||
local result
|
||||
local str="Checking integrity of existing gravity database"
|
||||
local option="${1}"
|
||||
echo -ne " ${INFO} ${str}..."
|
||||
if result="$(pihole-FTL sqlite3 "${gravityDBfile}" "PRAGMA integrity_check" 2>&1)"; then
|
||||
echo -e "${OVER} ${TICK} ${str} - no errors found"
|
||||
|
||||
str="Checking foreign keys of existing gravity database"
|
||||
echo -ne " ${INFO} ${str}..."
|
||||
if result="$(pihole-FTL sqlite3 "${gravityDBfile}" "PRAGMA foreign_key_check" 2>&1)"; then
|
||||
echo -e "${OVER} ${TICK} ${str} - no errors found"
|
||||
if [[ "${option}" != "force" ]]; then
|
||||
return
|
||||
fi
|
||||
else
|
||||
echo -e "${OVER} ${CROSS} ${str} - errors found:"
|
||||
while IFS= read -r line ; do echo " - $line"; done <<< "$result"
|
||||
fi
|
||||
else
|
||||
echo -e "${OVER} ${CROSS} ${str} - errors found:"
|
||||
while IFS= read -r line ; do echo " - $line"; done <<< "$result"
|
||||
fi
|
||||
|
||||
str="Trying to recover existing gravity database"
|
||||
echo -ne " ${INFO} ${str}..."
|
||||
# We have to remove any possibly existing recovery database or this will fail
|
||||
rm -f "${gravityDBfile}.recovered" > /dev/null 2>&1
|
||||
if result="$(pihole-FTL sqlite3 "${gravityDBfile}" ".recover" | pihole-FTL sqlite3 "${gravityDBfile}.recovered" 2>&1)"; then
|
||||
echo -e "${OVER} ${TICK} ${str} - success"
|
||||
mv "${gravityDBfile}" "${gravityDBfile}.old"
|
||||
mv "${gravityDBfile}.recovered" "${gravityDBfile}"
|
||||
echo -ne " ${INFO} ${gravityDBfile} has been recovered"
|
||||
echo -ne " ${INFO} The old ${gravityDBfile} has been moved to ${gravityDBfile}.old"
|
||||
else
|
||||
echo -e "${OVER} ${CROSS} ${str} - the following errors happened:"
|
||||
while IFS= read -r line ; do echo " - $line"; done <<< "$result"
|
||||
echo -e " ${CROSS} Recovery failed. Try \"pihole -r recreate\" instead."
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
helpFunc() {
|
||||
echo "Usage: pihole -g
|
||||
Update domains from blocklists specified in adlists.list
|
||||
@@ -920,51 +766,20 @@ Options:
|
||||
exit 0
|
||||
}
|
||||
|
||||
repairSelector() {
|
||||
case "$1" in
|
||||
"recover") recover_database=true;;
|
||||
"recreate") recreate_database=true;;
|
||||
*) echo "Usage: pihole -g -r {recover,recreate}
|
||||
Attempt to repair gravity database
|
||||
|
||||
Available options:
|
||||
pihole -g -r recover Try to recover a damaged gravity database file.
|
||||
Pi-hole tries to restore as much as possible
|
||||
from a corrupted gravity database.
|
||||
|
||||
pihole -g -r recover force Pi-hole will run the recovery process even when
|
||||
no damage is detected. This option is meant to be
|
||||
a last resort. Recovery is a fragile task
|
||||
consuming a lot of resources and shouldn't be
|
||||
performed unnecessarily.
|
||||
|
||||
pihole -g -r recreate Create a new gravity database file from scratch.
|
||||
This will remove your existing gravity database
|
||||
and create a new file from scratch. If you still
|
||||
have the migration backup created when migrating
|
||||
to Pi-hole v5.0, Pi-hole will import these files."
|
||||
exit 0;;
|
||||
esac
|
||||
}
|
||||
|
||||
for var in "$@"; do
|
||||
case "${var}" in
|
||||
"-f" | "--force" ) forceDelete=true;;
|
||||
"-r" | "--repair" ) repairSelector "$3";;
|
||||
"-o" | "--optimize" ) optimize_database=true;;
|
||||
"-r" | "--recreate" ) recreate_database=true;;
|
||||
"-h" | "--help" ) helpFunc;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Remove OLD (backup) gravity file, if it exists
|
||||
if [[ -f "${gravityOLDfile}" ]]; then
|
||||
rm "${gravityOLDfile}"
|
||||
fi
|
||||
|
||||
# Trap Ctrl-C
|
||||
gravity_Trap
|
||||
|
||||
if [[ "${recreate_database:-}" == true ]]; then
|
||||
str="Recreating gravity database from migration backup"
|
||||
str="Restoring from migration backup"
|
||||
echo -ne "${INFO} ${str}..."
|
||||
rm "${gravityDBfile}"
|
||||
pushd "${piholeDir}" > /dev/null || exit
|
||||
@@ -973,15 +788,8 @@ if [[ "${recreate_database:-}" == true ]]; then
|
||||
echo -e "${OVER} ${TICK} ${str}"
|
||||
fi
|
||||
|
||||
if [[ "${recover_database:-}" == true ]]; then
|
||||
database_recovery "$4"
|
||||
fi
|
||||
|
||||
# Move possibly existing legacy files to the gravity database
|
||||
if ! migrate_to_database; then
|
||||
echo -e " ${CROSS} Unable to migrate to database. Please contact support."
|
||||
exit 1
|
||||
fi
|
||||
migrate_to_database
|
||||
|
||||
if [[ "${forceDelete:-}" == true ]]; then
|
||||
str="Deleting existing list cache"
|
||||
@@ -992,21 +800,14 @@ if [[ "${forceDelete:-}" == true ]]; then
|
||||
fi
|
||||
|
||||
# Gravity downloads blocklists next
|
||||
if ! gravity_CheckDNSResolutionAvailable; then
|
||||
echo -e " ${CROSS} Can not complete gravity update, no DNS is available. Please contact support."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
gravity_CheckDNSResolutionAvailable
|
||||
gravity_DownloadBlocklists
|
||||
|
||||
# Create local.list
|
||||
gravity_generateLocalList
|
||||
|
||||
# Migrate rest of the data from old to new database
|
||||
if ! gravity_swap_databases; then
|
||||
echo -e " ${CROSS} Unable to create database. Please contact support."
|
||||
exit 1
|
||||
fi
|
||||
gravity_swap_databases
|
||||
|
||||
# Update gravity timestamp
|
||||
update_gravity_timestamp
|
||||
@@ -1018,6 +819,11 @@ chmod g+w "${piholeDir}" "${gravityDBfile}"
|
||||
# Compute numbers to be displayed
|
||||
gravity_ShowCount
|
||||
|
||||
# Optimize gravity database if requested
|
||||
if ${optimize_database} ; then
|
||||
gravity_Optimize
|
||||
fi
|
||||
|
||||
# Determine if DNS has been restarted by this instance of gravity
|
||||
if [[ -z "${dnsWasOffline:-}" ]]; then
|
||||
"${PIHOLE_COMMAND}" restartdns reload
|
||||
|
@@ -1,4 +1,4 @@
|
||||
.TH "Pihole-FTL" "8" "pihole-FTL" "Pi-hole" "November 2020"
|
||||
.TH "Pihole-FTL" "8" "pihole-FTL" "Pi-hole" "June 2018"
|
||||
.SH "NAME"
|
||||
pihole-FTL - Pi-hole : The Faster-Than-Light (FTL) Engine
|
||||
.br
|
||||
@@ -10,7 +10,7 @@ pihole-FTL - Pi-hole : The Faster-Than-Light (FTL) Engine
|
||||
.br
|
||||
\fBpihole-FTL test\fR
|
||||
.br
|
||||
\fBpihole-FTL -v|-vv\fR
|
||||
\fBpihole-FTL -v\fR
|
||||
.br
|
||||
\fBpihole-FTL -t\fR
|
||||
.br
|
||||
@@ -22,16 +22,6 @@ pihole-FTL - Pi-hole : The Faster-Than-Light (FTL) Engine
|
||||
.br
|
||||
\fBpihole-FTL dnsmasq-test\fR
|
||||
.br
|
||||
\fBpihole-FTL regex-test str\fR
|
||||
.br
|
||||
\fBpihole-FTL regex-test str rgx\fR
|
||||
.br
|
||||
\fBpihole-FTL lua\fR
|
||||
.br
|
||||
\fBpihole-FTL luac\fR
|
||||
.br
|
||||
\fBpihole-FTL dhcp-discover\fR
|
||||
.br
|
||||
\fBpihole-FTL --\fR (\fBoptions\fR)
|
||||
.br
|
||||
|
||||
@@ -75,11 +65,6 @@ Command line arguments
|
||||
Don't start FTL, show only version
|
||||
.br
|
||||
|
||||
\fB-vv\fR
|
||||
.br
|
||||
Don't start FTL, show verbose version information of embedded applications
|
||||
.br
|
||||
|
||||
\fB-t, tag\fR
|
||||
.br
|
||||
Don't start FTL, show only git tag
|
||||
@@ -105,31 +90,6 @@ Command line arguments
|
||||
Test resolver config file syntax
|
||||
.br
|
||||
|
||||
\fBregex-test str\fR
|
||||
.br
|
||||
Test str against all regular expressions in the database
|
||||
.br
|
||||
|
||||
\fBregex-test str rgx\fR
|
||||
.br
|
||||
Test str against regular expression given by rgx
|
||||
.br
|
||||
|
||||
\fBlua\fR
|
||||
.br
|
||||
Start the embedded Lua interpreter
|
||||
.br
|
||||
|
||||
\fBluac\fR
|
||||
.br
|
||||
Execute the embedded Lua compiler
|
||||
.br
|
||||
|
||||
\fBdhcp-discover\fR
|
||||
.br
|
||||
Discover DHCP servers in the local network
|
||||
.br
|
||||
|
||||
\fB--\fR (options)
|
||||
.br
|
||||
Pass options to internal dnsmasq resolver
|
||||
@@ -144,9 +104,7 @@ Command line arguments can be arbitrarily combined, e.g:
|
||||
Start ftl in foreground with more verbose logging, process everything and shutdown immediately
|
||||
.br
|
||||
.SH "SEE ALSO"
|
||||
\fBpihole\fR(8)
|
||||
.br
|
||||
\fBFor FTL's config options please see https://docs.pi-hole.net/ftldns/configfile/\fR
|
||||
\fBpihole\fR(8), \fBpihole-FTL.conf\fR(5)
|
||||
.br
|
||||
.SH "COLOPHON"
|
||||
|
||||
|
104
manpages/pihole-FTL.conf.5
Normal file
104
manpages/pihole-FTL.conf.5
Normal file
@@ -0,0 +1,104 @@
|
||||
.TH "pihole-FTL.conf" "5" "pihole-FTL.conf" "pihole-FTL.conf" "June 2018"
|
||||
.SH "NAME"
|
||||
|
||||
pihole-FTL.conf - FTL's config file
|
||||
.br
|
||||
.SH "DESCRIPTION"
|
||||
|
||||
/etc/pihole/pihole-FTL.conf will be read by \fBpihole-FTL(8)\fR on startup.
|
||||
.br
|
||||
|
||||
\fBSOCKET_LISTENING=localonly|all\fR
|
||||
.br
|
||||
Listen only for local socket connections or permit all connections
|
||||
.br
|
||||
|
||||
\fBQUERY_DISPLAY=yes|no\fR
|
||||
.br
|
||||
Display all queries? Set to no to hide query display
|
||||
.br
|
||||
|
||||
\fBAAAA_QUERY_ANALYSIS=yes|no\fR
|
||||
.br
|
||||
Allow FTL to analyze AAAA queries from pihole.log?
|
||||
.br
|
||||
|
||||
\fBRESOLVE_IPV6=yes|no\fR
|
||||
.br
|
||||
Should FTL try to resolve IPv6 addresses to host names?
|
||||
.br
|
||||
|
||||
\fBRESOLVE_IPV4=yes|no\fR
|
||||
.br
|
||||
Should FTL try to resolve IPv4 addresses to host names?
|
||||
.br
|
||||
|
||||
\fBMAXDBDAYS=365\fR
|
||||
.br
|
||||
How long should queries be stored in the database?
|
||||
.br
|
||||
Setting this to 0 disables the database
|
||||
.br
|
||||
|
||||
\fBDBINTERVAL=1.0\fR
|
||||
.br
|
||||
How often do we store queries in FTL's database [minutes]?
|
||||
.br
|
||||
|
||||
\fBDBFILE=/etc/pihole/pihole-FTL.db\fR
|
||||
.br
|
||||
Specify path and filename of FTL's SQLite long-term database.
|
||||
.br
|
||||
Setting this to DBFILE= disables the database altogether
|
||||
.br
|
||||
|
||||
\fBMAXLOGAGE=24.0\fR
|
||||
.br
|
||||
Up to how many hours of queries should be imported from the database and logs?
|
||||
.br
|
||||
Maximum is 744 (31 days)
|
||||
.br
|
||||
|
||||
\fBFTLPORT=4711\fR
|
||||
.br
|
||||
On which port should FTL be listening?
|
||||
.br
|
||||
|
||||
\fBPRIVACYLEVEL=0|1|2|3|4\fR
|
||||
.br
|
||||
Which privacy level is used?
|
||||
.br
|
||||
0 - show everything
|
||||
.br
|
||||
1 - hide domains
|
||||
.br
|
||||
2 - hide domains and clients
|
||||
.br
|
||||
3 - anonymous mode (hide everything)
|
||||
.br
|
||||
4 - disable all statistics
|
||||
.br
|
||||
|
||||
\fBIGNORE_LOCALHOST=no|yes\fR
|
||||
.br
|
||||
Should FTL ignore queries coming from the local machine?
|
||||
.br
|
||||
|
||||
\fBBLOCKINGMODE=IP|IP-AAAA-NODATA|NXDOMAIN|NULL\fR
|
||||
.br
|
||||
How should FTL reply to blocked queries?
|
||||
.br
|
||||
|
||||
For each setting, the option shown first is the default.
|
||||
.br
|
||||
.SH "SEE ALSO"
|
||||
|
||||
\fBpihole\fR(8), \fBpihole-FTL\fR(8)
|
||||
.br
|
||||
.SH "COLOPHON"
|
||||
|
||||
Pi-hole : The Faster-Than-Light (FTL) Engine is a lightweight, purpose-built daemon used to provide statistics needed for the Pi-hole Web Interface, and its API can be easily integrated into your own projects. Although it is an optional component of the Pi-hole ecosystem, it will be installed by default to provide statistics. As the name implies, FTL does its work \fIvery quickly\fR!
|
||||
.br
|
||||
|
||||
Get sucked into the latest news and community activity by entering Pi-hole's orbit. Information about Pi-hole, and the latest version of the software can be found at https://pi-hole.net
|
||||
.br
|
@@ -56,7 +56,7 @@ Available commands and options:
|
||||
|
||||
\fB-w, whitelist\fR [options] [<domain1> <domain2 ...>]
|
||||
.br
|
||||
Adds or removes specified domain or domains to the Whitelist
|
||||
Adds or removes specified domain or domains tho the Whitelist
|
||||
.br
|
||||
|
||||
\fB-b, blacklist\fR [options] [<domain1> <domain2 ...>]
|
||||
@@ -139,7 +139,7 @@ Available commands and options:
|
||||
-i, interface Specify dnsmasq's interface listening behavior
|
||||
.br
|
||||
-l, privacylevel <level> Set privacy level
|
||||
(0 = lowest, 3 = highest)
|
||||
(0 = lowest, 4 = highest)
|
||||
.br
|
||||
|
||||
\fB-c, chronometer\fR [options]
|
||||
@@ -153,7 +153,7 @@ Available commands and options:
|
||||
.br
|
||||
-r, --refresh Set update frequency (in seconds)
|
||||
.br
|
||||
-e, --exit Output stats and exit without refreshing
|
||||
-e, --exit Output stats and exit witout refreshing
|
||||
.br
|
||||
|
||||
\fB-g, updateGravity\fR
|
||||
|
225
pihole
225
pihole
@@ -16,14 +16,10 @@ readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
||||
# error due to modifying a readonly variable.
|
||||
setupVars="/etc/pihole/setupVars.conf"
|
||||
PI_HOLE_BIN_DIR="/usr/local/bin"
|
||||
readonly FTL_PID_FILE="/run/pihole-FTL.pid"
|
||||
|
||||
readonly colfile="${PI_HOLE_SCRIPT_DIR}/COL_TABLE"
|
||||
source "${colfile}"
|
||||
|
||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
||||
source "${utilsfile}"
|
||||
|
||||
webpageFunc() {
|
||||
source "${PI_HOLE_SCRIPT_DIR}/webpage.sh"
|
||||
main "$@"
|
||||
@@ -74,7 +70,8 @@ reconfigurePiholeFunc() {
|
||||
}
|
||||
|
||||
updateGravityFunc() {
|
||||
exec "${PI_HOLE_SCRIPT_DIR}"/gravity.sh "$@"
|
||||
"${PI_HOLE_SCRIPT_DIR}"/gravity.sh "$@"
|
||||
exit $?
|
||||
}
|
||||
|
||||
queryFunc() {
|
||||
@@ -97,28 +94,12 @@ uninstallFunc() {
|
||||
|
||||
versionFunc() {
|
||||
shift
|
||||
exec "${PI_HOLE_SCRIPT_DIR}"/version.sh "$@"
|
||||
}
|
||||
|
||||
# Get PID of main pihole-FTL process
|
||||
getFTLPID() {
|
||||
local pid
|
||||
|
||||
if [ -s "${FTL_PID_FILE}" ]; then
|
||||
# -s: FILE exists and has a size greater than zero
|
||||
pid="$(<"$FTL_PID_FILE")"
|
||||
# Exploit prevention: unset the variable if there is malicious content
|
||||
# Verify that the value read from the file is numeric
|
||||
[[ "$pid" =~ [^[:digit:]] ]] && unset pid
|
||||
fi
|
||||
|
||||
# If FTL is not running, or the PID file contains malicious stuff, substitute
|
||||
# negative PID to signal this to the caller
|
||||
echo "${pid:=-1}"
|
||||
"${PI_HOLE_SCRIPT_DIR}"/version.sh "$@"
|
||||
exit 0
|
||||
}
|
||||
|
||||
restartDNS() {
|
||||
local svcOption svc str output status pid icon
|
||||
local svcOption svc str output status
|
||||
svcOption="${1:-restart}"
|
||||
|
||||
# Determine if we should reload or restart
|
||||
@@ -127,34 +108,17 @@ restartDNS() {
|
||||
# Note 1: This will NOT re-read any *.conf files
|
||||
# Note 2: We cannot use killall here as it does
|
||||
# not know about real-time signals
|
||||
pid="$(getFTLPID)"
|
||||
if [[ "$pid" -eq "-1" ]]; then
|
||||
svc="true"
|
||||
str="FTL is not running"
|
||||
icon="${INFO}"
|
||||
else
|
||||
svc="kill -RTMIN ${pid}"
|
||||
str="Reloading DNS lists"
|
||||
icon="${TICK}"
|
||||
fi
|
||||
svc="pkill -RTMIN pihole-FTL"
|
||||
str="Reloading DNS lists"
|
||||
elif [[ "${svcOption}" =~ "reload" ]]; then
|
||||
# Reloading of the DNS cache has been requested
|
||||
# Note: This will NOT re-read any *.conf files
|
||||
pid="$(getFTLPID)"
|
||||
if [[ "$pid" -eq "-1" ]]; then
|
||||
svc="true"
|
||||
str="FTL is not running"
|
||||
icon="${INFO}"
|
||||
else
|
||||
svc="kill -HUP ${pid}"
|
||||
str="Flushing DNS cache"
|
||||
icon="${TICK}"
|
||||
fi
|
||||
svc="pkill -HUP pihole-FTL"
|
||||
str="Flushing DNS cache"
|
||||
else
|
||||
# A full restart has been requested
|
||||
svc="service pihole-FTL restart"
|
||||
str="Restarting DNS server"
|
||||
icon="${TICK}"
|
||||
fi
|
||||
|
||||
# Print output to Terminal, but not to Web Admin
|
||||
@@ -164,7 +128,7 @@ restartDNS() {
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -eq 0 ]]; then
|
||||
[[ -t 1 ]] && echo -e "${OVER} ${icon} ${str}"
|
||||
[[ -t 1 ]] && echo -e "${OVER} ${TICK} ${str}"
|
||||
return 0
|
||||
else
|
||||
[[ ! -t 1 ]] && local OVER=""
|
||||
@@ -226,7 +190,8 @@ Time:
|
||||
fi
|
||||
|
||||
local str="Pi-hole Disabled"
|
||||
addOrEditKeyValPair "${setupVars}" "BLOCKING_ENABLED" "false"
|
||||
sed -i "/BLOCKING_ENABLED=/d" "${setupVars}"
|
||||
echo "BLOCKING_ENABLED=false" >> "${setupVars}"
|
||||
fi
|
||||
else
|
||||
# Enable Pi-hole
|
||||
@@ -238,10 +203,11 @@ Time:
|
||||
echo -e " ${INFO} Enabling blocking"
|
||||
local str="Pi-hole Enabled"
|
||||
|
||||
addOrEditKeyValPair "${setupVars}" "BLOCKING_ENABLED" "true"
|
||||
sed -i "/BLOCKING_ENABLED=/d" "${setupVars}"
|
||||
echo "BLOCKING_ENABLED=true" >> "${setupVars}"
|
||||
fi
|
||||
|
||||
restartDNS reload-lists
|
||||
restartDNS reload
|
||||
|
||||
echo -e "${OVER} ${TICK} ${str}"
|
||||
}
|
||||
@@ -260,8 +226,8 @@ Options:
|
||||
exit 0
|
||||
elif [[ "${1}" == "off" ]]; then
|
||||
# Disable logging
|
||||
addOrEditKeyValPair /etc/dnsmasq.d/01-pihole.conf "log-queries"
|
||||
addOrEditKeyValPair "${setupVars}" "QUERY_LOGGING" "false"
|
||||
sed -i 's/^log-queries/#log-queries/' /etc/dnsmasq.d/01-pihole.conf
|
||||
sed -i 's/^QUERY_LOGGING=true/QUERY_LOGGING=false/' /etc/pihole/setupVars.conf
|
||||
if [[ "${2}" != "noflush" ]]; then
|
||||
# Flush logs
|
||||
"${PI_HOLE_BIN_DIR}"/pihole -f
|
||||
@@ -270,8 +236,8 @@ Options:
|
||||
local str="Logging has been disabled!"
|
||||
elif [[ "${1}" == "on" ]]; then
|
||||
# Enable logging
|
||||
removeKey /etc/dnsmasq.d/01-pihole.conf "log-queries"
|
||||
addOrEditKeyValPair "${setupVars}" "QUERY_LOGGING" "true"
|
||||
sed -i 's/^#log-queries/log-queries/' /etc/dnsmasq.d/01-pihole.conf
|
||||
sed -i 's/^QUERY_LOGGING=false/QUERY_LOGGING=true/' /etc/pihole/setupVars.conf
|
||||
echo -e " ${INFO} Enabling logging..."
|
||||
local str="Logging has been enabled!"
|
||||
else
|
||||
@@ -283,64 +249,18 @@ Options:
|
||||
echo -e "${OVER} ${TICK} ${str}"
|
||||
}
|
||||
|
||||
analyze_ports() {
|
||||
local lv4 lv6 port=${1}
|
||||
# FTL is listening at least on at least one port when this
|
||||
# function is getting called
|
||||
# Check individual address family/protocol combinations
|
||||
# For a healthy Pi-hole, they should all be up (nothing printed)
|
||||
lv4="$(ss --ipv4 --listening --numeric --tcp --udp src :${port})"
|
||||
if grep -q "udp " <<< "${lv4}"; then
|
||||
echo -e " ${TICK} UDP (IPv4)"
|
||||
else
|
||||
echo -e " ${CROSS} UDP (IPv4)"
|
||||
fi
|
||||
if grep -q "tcp " <<< "${lv4}"; then
|
||||
echo -e " ${TICK} TCP (IPv4)"
|
||||
else
|
||||
echo -e " ${CROSS} TCP (IPv4)"
|
||||
fi
|
||||
lv6="$(ss --ipv6 --listening --numeric --tcp --udp src :${port})"
|
||||
if grep -q "udp " <<< "${lv6}"; then
|
||||
echo -e " ${TICK} UDP (IPv6)"
|
||||
else
|
||||
echo -e " ${CROSS} UDP (IPv6)"
|
||||
fi
|
||||
if grep -q "tcp " <<< "${lv6}"; then
|
||||
echo -e " ${TICK} TCP (IPv6)"
|
||||
else
|
||||
echo -e " ${CROSS} TCP (IPv6)"
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
statusFunc() {
|
||||
# Determine if there is pihole-FTL service is listening
|
||||
local pid port ftl_api_port
|
||||
|
||||
pid="$(getFTLPID)"
|
||||
ftl_api_port="$(getFTLAPIPort)"
|
||||
if [[ "$pid" -eq "-1" ]]; then
|
||||
# Determine if service is running on port 53 (Cr: https://superuser.com/a/806331)
|
||||
if (echo > /dev/tcp/127.0.0.1/53) >/dev/null 2>&1; then
|
||||
if [[ "${1}" != "web" ]]; then
|
||||
echo -e " ${TICK} DNS service is running"
|
||||
fi
|
||||
else
|
||||
case "${1}" in
|
||||
"web") echo "-1";;
|
||||
*) echo -e " ${CROSS} DNS service is NOT running";;
|
||||
esac
|
||||
return 0
|
||||
else
|
||||
#get the DNS port pihole-FTL is listening on by using FTL's telnet API
|
||||
port="$(echo ">dns-port >quit" | nc 127.0.0.1 "$ftl_api_port")"
|
||||
if [[ "${port}" == "0" ]]; then
|
||||
case "${1}" in
|
||||
"web") echo "-1";;
|
||||
*) echo -e " ${CROSS} DNS service is NOT listening";;
|
||||
esac
|
||||
return 0
|
||||
else
|
||||
if [[ "${1}" != "web" ]]; then
|
||||
echo -e " ${TICK} FTL is listening on port ${port}"
|
||||
analyze_ports "${port}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Determine if Pi-hole's blocking is enabled
|
||||
@@ -348,24 +268,23 @@ statusFunc() {
|
||||
# A config is commented out
|
||||
case "${1}" in
|
||||
"web") echo 0;;
|
||||
*) echo -e " ${CROSS} Pi-hole blocking is disabled";;
|
||||
*) echo -e " ${CROSS} Pi-hole blocking is Disabled";;
|
||||
esac
|
||||
elif grep -q "BLOCKING_ENABLED=true" /etc/pihole/setupVars.conf; then
|
||||
# Configs are set
|
||||
case "${1}" in
|
||||
"web") echo "$port";;
|
||||
*) echo -e " ${TICK} Pi-hole blocking is enabled";;
|
||||
"web") echo 1;;
|
||||
*) echo -e " ${TICK} Pi-hole blocking is Enabled";;
|
||||
esac
|
||||
else
|
||||
# No configs were found
|
||||
case "${1}" in
|
||||
"web") echo -2;;
|
||||
"web") echo 99;;
|
||||
*) echo -e " ${INFO} Pi-hole blocking will be enabled";;
|
||||
esac
|
||||
# Enable blocking
|
||||
"${PI_HOLE_BIN_DIR}"/pihole enable
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
tailFunc() {
|
||||
@@ -378,13 +297,16 @@ tailFunc() {
|
||||
fi
|
||||
echo -e " ${INFO} Press Ctrl-C to exit"
|
||||
|
||||
# Retrieve IPv4/6 addresses
|
||||
source /etc/pihole/setupVars.conf
|
||||
|
||||
# Strip date from each line
|
||||
# Color blocklist/blacklist/wildcard entries as red
|
||||
# Color A/AAAA/DHCP strings as white
|
||||
# Color everything else as gray
|
||||
tail -f /var/log/pihole.log | grep --line-buffered "${1}" | sed -E \
|
||||
tail -f /var/log/pihole.log | sed -E \
|
||||
-e "s,($(date +'%b %d ')| dnsmasq\[[0-9]*\]),,g" \
|
||||
-e "s,(.*(blacklisted |gravity blocked ).*),${COL_RED}&${COL_NC}," \
|
||||
-e "s,(.*(blacklisted |gravity blocked ).* is (0.0.0.0|::|NXDOMAIN|${IPV4_ADDRESS%/*}|${IPV6_ADDRESS:-NULL}).*),${COL_RED}&${COL_NC}," \
|
||||
-e "s,.*(query\\[A|DHCP).*,${COL_NC}&${COL_NC}," \
|
||||
-e "s,.*,${COL_GRAY}&${COL_NC},"
|
||||
exit 0
|
||||
@@ -414,24 +336,34 @@ Branches:
|
||||
}
|
||||
|
||||
tricorderFunc() {
|
||||
local tricorder_token
|
||||
if [[ ! -p "/dev/stdin" ]]; then
|
||||
echo -e " ${INFO} Please do not call Tricorder directly"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tricorder_token=$(curl --silent --fail --show-error --upload-file "-" https://tricorder.pi-hole.net/upload < /dev/stdin 2>&1)
|
||||
if [[ "${tricorder_token}" != "https://tricorder.pi-hole.net/"* ]]; then
|
||||
echo -e "${CROSS} uploading failed, contact Pi-hole support for assistance."
|
||||
# Log curl error (if available)
|
||||
if [ -n "${tricorder_token}" ]; then
|
||||
echo -e "${INFO} Error message: ${COL_RED}${tricorder_token}${COL_NC}\\n"
|
||||
tricorder_token=""
|
||||
fi
|
||||
exit 1
|
||||
if ! (echo > /dev/tcp/tricorder.pi-hole.net/9998) >/dev/null 2>&1; then
|
||||
echo -e " ${CROSS} Unable to connect to Pi-hole's Tricorder server"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if command -v openssl &> /dev/null; then
|
||||
openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin
|
||||
exit "$?"
|
||||
else
|
||||
echo -e " ${INFO} ${COL_YELLOW}Security Notice${COL_NC}: ${COL_WHITE}openssl${COL_NC} is not installed
|
||||
Your debug log will be transmitted unencrypted via plain-text
|
||||
There is a possibility that this could be intercepted by a third party
|
||||
If you wish to cancel, press Ctrl-C to exit within 10 seconds"
|
||||
secs="10"
|
||||
while [[ "$secs" -gt "0" ]]; do
|
||||
echo -ne "."
|
||||
sleep 1
|
||||
: $((secs--))
|
||||
done
|
||||
echo " "
|
||||
nc tricorder.pi-hole.net 9999 < /dev/stdin
|
||||
exit "$?"
|
||||
fi
|
||||
echo "Upload successful, your token is: ${COL_GREEN}${tricorder_token}${COL_NC}"
|
||||
exit 0
|
||||
}
|
||||
|
||||
updateCheckFunc() {
|
||||
@@ -455,13 +387,10 @@ Whitelist/Blacklist Options:
|
||||
|
||||
Debugging Options:
|
||||
-d, debug Start a debugging session
|
||||
Add '-a' to automatically upload the log to tricorder.pi-hole.net
|
||||
Add '-a' to enable automated debugging
|
||||
-f, flush Flush the Pi-hole log
|
||||
-r, reconfigure Reconfigure or Repair Pi-hole subsystems
|
||||
-t, tail [arg] View the live output of the Pi-hole log.
|
||||
Add an optional argument to filter the log
|
||||
(regular expressions are supported)
|
||||
|
||||
-t, tail View the live output of the Pi-hole log
|
||||
|
||||
Options:
|
||||
-a, admin Web interface options
|
||||
@@ -496,38 +425,8 @@ if [[ $# = 0 ]]; then
|
||||
helpFunc
|
||||
fi
|
||||
|
||||
# functions that do not require sudo power
|
||||
case "${1}" in
|
||||
"-h" | "help" | "--help" ) helpFunc;;
|
||||
"-v" | "version" ) versionFunc "$@";;
|
||||
"-c" | "chronometer" ) chronometerFunc "$@";;
|
||||
"-q" | "query" ) queryFunc "$@";;
|
||||
"status" ) statusFunc "$2";;
|
||||
"-t" | "tail" ) tailFunc "$2";;
|
||||
"tricorder" ) tricorderFunc;;
|
||||
|
||||
# we need to add all arguments that require sudo power to not trigger the * argument
|
||||
"-w" | "whitelist" ) ;;
|
||||
"-b" | "blacklist" ) ;;
|
||||
"--wild" | "wildcard" ) ;;
|
||||
"--regex" | "regex" ) ;;
|
||||
"--white-regex" | "white-regex" ) ;;
|
||||
"--white-wild" | "white-wild" ) ;;
|
||||
"-f" | "flush" ) ;;
|
||||
"-up" | "updatePihole" ) ;;
|
||||
"-r" | "reconfigure" ) ;;
|
||||
"-g" | "updateGravity" ) ;;
|
||||
"-l" | "logging" ) ;;
|
||||
"uninstall" ) ;;
|
||||
"enable" ) ;;
|
||||
"disable" ) ;;
|
||||
"-d" | "debug" ) ;;
|
||||
"restartdns" ) ;;
|
||||
"-a" | "admin" ) ;;
|
||||
"checkout" ) ;;
|
||||
"updatechecker" ) ;;
|
||||
"arpflush" ) ;;
|
||||
* ) helpFunc;;
|
||||
esac
|
||||
|
||||
# Must be root to use this tool
|
||||
@@ -554,13 +453,21 @@ case "${1}" in
|
||||
"-up" | "updatePihole" ) updatePiholeFunc "$@";;
|
||||
"-r" | "reconfigure" ) reconfigurePiholeFunc;;
|
||||
"-g" | "updateGravity" ) updateGravityFunc "$@";;
|
||||
"-c" | "chronometer" ) chronometerFunc "$@";;
|
||||
"-h" | "help" ) helpFunc;;
|
||||
"-v" | "version" ) versionFunc "$@";;
|
||||
"-q" | "query" ) queryFunc "$@";;
|
||||
"-l" | "logging" ) piholeLogging "$@";;
|
||||
"uninstall" ) uninstallFunc;;
|
||||
"enable" ) piholeEnable 1;;
|
||||
"disable" ) piholeEnable 0 "$2";;
|
||||
"status" ) statusFunc "$2";;
|
||||
"restartdns" ) restartDNS "$2";;
|
||||
"-a" | "admin" ) webpageFunc "$@";;
|
||||
"-t" | "tail" ) tailFunc;;
|
||||
"checkout" ) piholeCheckoutFunc "$@";;
|
||||
"tricorder" ) tricorderFunc;;
|
||||
"updatechecker" ) updateCheckFunc "$@";;
|
||||
"arpflush" ) arpFunc "$@";;
|
||||
* ) helpFunc;;
|
||||
esac
|
||||
|
6
requirements.txt
Normal file
6
requirements.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
docker-compose==1.23.2
|
||||
pytest==4.3.0
|
||||
pytest-xdist==1.26.1
|
||||
pytest-cov==2.6.1
|
||||
testinfra==1.19.0
|
||||
tox==3.7.0
|
5
supportedos.txt
Normal file
5
supportedos.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Raspbian=9,10
|
||||
Ubuntu=16,18,20
|
||||
Debian=9,10
|
||||
Fedora=31,32
|
||||
CentOS=7,8
|
@@ -18,8 +18,8 @@ py.test -vv -n auto -m "build_stage"
|
||||
py.test -vv -n auto -m "not build_stage"
|
||||
```
|
||||
|
||||
The build_stage tests have to run first to create the docker images, followed by the actual tests which utilize said images. Unless you're changing your dockerfiles you shouldn't have to run the build_stage every time - but it's a good idea to rebuild at least once a day in case the base Docker images or packages change.
|
||||
The build_stage tests have to run first to create the docker images, followed by the actual tests which utilize said images. Unless you're changing your dockerfiles you shouldn't have to run the build_stage every time - but it's a good idea to rebuild at least once a day in case the base Docker images or packages change.
|
||||
|
||||
# How do I debug python?
|
||||
|
||||
Highly recommended: Setup PyCharm on a **Docker enabled** machine. Having a python debugger like PyCharm changes your life if you've never used it :)
|
||||
Highly recommended: Setup PyCharm on a **Docker enabled** machine. Having a python debugger like PyCharm changes your life if you've never used it :)
|
||||
|
@@ -1,18 +0,0 @@
|
||||
FROM quay.io/centos/centos:stream8
|
||||
RUN yum install -y git
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
|
||||
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
||||
ADD . $GITDIR
|
||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
|
||||
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
@@ -1,17 +0,0 @@
|
||||
FROM buildpack-deps:bullseye-scm
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
|
||||
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
||||
ADD . $GITDIR
|
||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
|
||||
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
@@ -1,17 +0,0 @@
|
||||
FROM buildpack-deps:stretch-scm
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
|
||||
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
||||
ADD . $GITDIR
|
||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
|
||||
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
@@ -1,18 +0,0 @@
|
||||
FROM fedora:33
|
||||
RUN dnf install -y git
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
|
||||
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
||||
ADD . $GITDIR
|
||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
|
||||
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
@@ -1,18 +0,0 @@
|
||||
FROM fedora:34
|
||||
RUN dnf install -y git
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
|
||||
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
||||
ADD . $GITDIR
|
||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
|
||||
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
@@ -1,17 +0,0 @@
|
||||
FROM buildpack-deps:xenial-scm
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
|
||||
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
||||
ADD . $GITDIR
|
||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
|
||||
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
@@ -1,18 +0,0 @@
|
||||
FROM buildpack-deps:focal-scm
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
|
||||
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
||||
ADD . $GITDIR
|
||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
|
||||
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
@@ -1,18 +0,0 @@
|
||||
FROM buildpack-deps:impish-scm
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
|
||||
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
||||
ADD . $GITDIR
|
||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
|
||||
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
@@ -1,5 +1,4 @@
|
||||
FROM centos:7
|
||||
RUN yum install -y git
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
@@ -13,6 +12,5 @@ RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
164
test/conftest.py
164
test/conftest.py
@@ -1,52 +1,96 @@
|
||||
import pytest
|
||||
import testinfra
|
||||
import testinfra.backend.docker
|
||||
import subprocess
|
||||
from textwrap import dedent
|
||||
|
||||
check_output = testinfra.get_backend(
|
||||
"local://"
|
||||
).get_module("Command").check_output
|
||||
|
||||
SETUPVARS = {
|
||||
'PIHOLE_INTERFACE': 'eth99',
|
||||
'IPV4_ADDRESS': '1.1.1.1',
|
||||
'IPV6_ADDRESS': 'FE80::240:D0FF:FE48:4672',
|
||||
'PIHOLE_DNS_1': '4.2.2.1',
|
||||
'PIHOLE_DNS_2': '4.2.2.2'
|
||||
}
|
||||
|
||||
IMAGE = 'pytest_pihole:test_container'
|
||||
|
||||
tick_box = "[\x1b[1;32m\u2713\x1b[0m]"
|
||||
cross_box = "[\x1b[1;31m\u2717\x1b[0m]"
|
||||
info_box = "[i]"
|
||||
|
||||
|
||||
# Monkeypatch sh to bash, if they ever support non hard code /bin/sh this can go away
|
||||
# https://github.com/pytest-dev/pytest-testinfra/blob/master/testinfra/backend/docker.py
|
||||
def run_bash(self, command, *args, **kwargs):
|
||||
cmd = self.get_command(command, *args)
|
||||
if self.user is not None:
|
||||
out = self.run_local(
|
||||
"docker exec -u %s %s /bin/bash -c %s", self.user, self.name, cmd
|
||||
)
|
||||
else:
|
||||
out = self.run_local("docker exec %s /bin/bash -c %s", self.name, cmd)
|
||||
out.command = self.encode(cmd)
|
||||
return out
|
||||
@pytest.fixture
|
||||
def Pihole(Docker):
|
||||
'''
|
||||
used to contain some script stubbing, now pretty much an alias.
|
||||
Also provides bash as the default run function shell
|
||||
'''
|
||||
def run_bash(self, command, *args, **kwargs):
|
||||
cmd = self.get_command(command, *args)
|
||||
if self.user is not None:
|
||||
out = self.run_local(
|
||||
"docker exec -u %s %s /bin/bash -c %s",
|
||||
self.user, self.name, cmd)
|
||||
else:
|
||||
out = self.run_local(
|
||||
"docker exec %s /bin/bash -c %s", self.name, cmd)
|
||||
out.command = self.encode(cmd)
|
||||
return out
|
||||
|
||||
|
||||
testinfra.backend.docker.DockerBackend.run = run_bash
|
||||
funcType = type(Docker.run)
|
||||
Docker.run = funcType(run_bash, Docker)
|
||||
return Docker
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def host():
|
||||
# run a container
|
||||
docker_id = subprocess.check_output(
|
||||
['docker', 'run', '-t', '-d', '--cap-add=ALL', IMAGE]).decode().strip()
|
||||
def Docker(request, args, image, cmd):
|
||||
'''
|
||||
combine our fixtures into a docker run command and setup finalizer to
|
||||
cleanup
|
||||
'''
|
||||
assert 'docker' in check_output('id'), "Are you in the docker group?"
|
||||
docker_run = "docker run {} {} {}".format(args, image, cmd)
|
||||
docker_id = check_output(docker_run)
|
||||
|
||||
# return a testinfra connection to the container
|
||||
docker_host = testinfra.get_host("docker://" + docker_id)
|
||||
def teardown():
|
||||
check_output("docker rm -f %s", docker_id)
|
||||
request.addfinalizer(teardown)
|
||||
|
||||
yield docker_host
|
||||
# at the end of the test suite, destroy the container
|
||||
subprocess.check_call(['docker', 'rm', '-f', docker_id])
|
||||
docker_container = testinfra.get_backend("docker://" + docker_id)
|
||||
docker_container.id = docker_id
|
||||
return docker_container
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def args(request):
|
||||
'''
|
||||
-t became required when tput began being used
|
||||
'''
|
||||
return '-t -d'
|
||||
|
||||
|
||||
@pytest.fixture(params=['debian', 'centos', 'fedora'])
|
||||
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
|
||||
@@ -56,7 +100,7 @@ def mock_command(script, args, container):
|
||||
in unit tests
|
||||
'''
|
||||
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||
mock_script = dedent(r'''\
|
||||
mock_script = dedent('''\
|
||||
#!/bin/bash -e
|
||||
echo "\$0 \$@" >> /var/log/{script}
|
||||
case "\$1" in'''.format(script=script))
|
||||
@@ -77,75 +121,13 @@ def mock_command(script, args, container):
|
||||
scriptlog=script))
|
||||
|
||||
|
||||
def mock_command_passthrough(script, args, container):
|
||||
'''
|
||||
Per other mock_command* functions, allows intercepting of commands we don't want to run for real
|
||||
in unit tests, however also allows only specific arguments to be mocked. Anything not defined will
|
||||
be passed through to the actual command.
|
||||
|
||||
Example use-case: mocking `git pull` but still allowing `git clone` to work as intended
|
||||
'''
|
||||
orig_script_path = container.check_output('command -v {}'.format(script))
|
||||
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||
mock_script = dedent(r'''\
|
||||
#!/bin/bash -e
|
||||
echo "\$0 \$@" >> /var/log/{script}
|
||||
case "\$1" in'''.format(script=script))
|
||||
for k, v in args.items():
|
||||
case = dedent('''
|
||||
{arg})
|
||||
echo {res}
|
||||
exit {retcode}
|
||||
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
||||
mock_script += case
|
||||
mock_script += dedent(r'''
|
||||
*)
|
||||
{orig_script_path} "\$@"
|
||||
;;'''.format(orig_script_path=orig_script_path))
|
||||
mock_script += dedent('''
|
||||
esac''')
|
||||
container.run('''
|
||||
cat <<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):
|
||||
'''
|
||||
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'''\
|
||||
mock_script = dedent('''\
|
||||
#!/bin/bash -e
|
||||
echo "\$0 \$@" >> /var/log/{script}
|
||||
case "\$1 \$2" in'''.format(script=script))
|
||||
|
@@ -1,4 +1,4 @@
|
||||
FROM buildpack-deps:buster-scm
|
||||
FROM buildpack-deps:jessie-scm
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
@@ -12,6 +12,5 @@ RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
@@ -1,4 +1,4 @@
|
||||
FROM buildpack-deps:bionic-scm
|
||||
FROM fedora:30
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
@@ -12,6 +12,5 @@ RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
@@ -1,6 +0,0 @@
|
||||
docker-compose
|
||||
pytest
|
||||
pytest-xdist
|
||||
pytest-cov
|
||||
pytest-testinfra
|
||||
tox
|
23
test/test_000_build_containers.py
Normal file
23
test/test_000_build_containers.py
Normal file
@@ -0,0 +1,23 @@
|
||||
''' This file starts with 000 to make it run first '''
|
||||
import pytest
|
||||
import testinfra
|
||||
|
||||
run_local = testinfra.get_backend(
|
||||
"local://"
|
||||
).get_module("Command").run
|
||||
|
||||
|
||||
@pytest.mark.parametrize("image,tag", [
|
||||
('test/debian.Dockerfile', 'pytest_pihole:debian'),
|
||||
('test/centos.Dockerfile', 'pytest_pihole:centos'),
|
||||
('test/fedora.Dockerfile', 'pytest_pihole:fedora'),
|
||||
])
|
||||
# mark as 'build_stage' so we can ensure images are build first when tests
|
||||
# are executed in parallel. (not required when tests are executed serially)
|
||||
@pytest.mark.build_stage
|
||||
def test_build_pihole_image(image, tag):
|
||||
build_cmd = run_local('docker build -f {} -t {} .'.format(image, tag))
|
||||
if build_cmd.rc != 0:
|
||||
print(build_cmd.stdout)
|
||||
print(build_cmd.stderr)
|
||||
assert build_cmd.rc == 0
|
File diff suppressed because it is too large
Load Diff
@@ -1,56 +0,0 @@
|
||||
def test_key_val_replacement_works(host):
|
||||
''' Confirms addOrEditKeyValPair provides the expected output '''
|
||||
host.run('''
|
||||
source /opt/pihole/utils.sh
|
||||
addOrEditKeyValPair "./testoutput" "KEY_ONE" "value1"
|
||||
addOrEditKeyValPair "./testoutput" "KEY_TWO" "value2"
|
||||
addOrEditKeyValPair "./testoutput" "KEY_ONE" "value3"
|
||||
addOrEditKeyValPair "./testoutput" "KEY_FOUR" "value4"
|
||||
addOrEditKeyValPair "./testoutput" "KEY_FIVE_NO_VALUE"
|
||||
addOrEditKeyValPair "./testoutput" "KEY_FIVE_NO_VALUE"
|
||||
''')
|
||||
output = host.run('''
|
||||
cat ./testoutput
|
||||
''')
|
||||
expected_stdout = 'KEY_ONE=value3\nKEY_TWO=value2\nKEY_FOUR=value4\nKEY_FIVE_NO_VALUE\n'
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_key_val_removal_works(host):
|
||||
''' Confirms removeKey provides the expected output '''
|
||||
host.run('''
|
||||
source /opt/pihole/utils.sh
|
||||
addOrEditKeyValPair "./testoutput" "KEY_ONE" "value1"
|
||||
addOrEditKeyValPair "./testoutput" "KEY_TWO" "value2"
|
||||
addOrEditKeyValPair "./testoutput" "KEY_THREE" "value3"
|
||||
removeKey "./testoutput" "KEY_TWO"
|
||||
''')
|
||||
output = host.run('''
|
||||
cat ./testoutput
|
||||
''')
|
||||
expected_stdout = 'KEY_ONE=value1\nKEY_THREE=value3\n'
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_getFTLAPIPort_default(host):
|
||||
''' Confirms getFTLAPIPort returns the default API port '''
|
||||
output = host.run('''
|
||||
source /opt/pihole/utils.sh
|
||||
getFTLAPIPort
|
||||
''')
|
||||
expected_stdout = '4711\n'
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_getFTLAPIPort_custom(host):
|
||||
''' Confirms getFTLAPIPort returns a custom API port in a custom PORTFILE location '''
|
||||
host.run('''
|
||||
echo "PORTFILE=/tmp/port.file" > /etc/pihole/pihole-FTL.conf
|
||||
echo "1234" > /tmp/port.file
|
||||
''')
|
||||
output = host.run('''
|
||||
source /opt/pihole/utils.sh
|
||||
getFTLAPIPort
|
||||
''')
|
||||
expected_stdout = '1234\n'
|
||||
assert expected_stdout == output.stdout
|
490
test/test_automated_install.py
Normal file
490
test/test_automated_install.py
Normal file
@@ -0,0 +1,490 @@
|
||||
from textwrap import dedent
|
||||
import re
|
||||
from .conftest import (
|
||||
SETUPVARS,
|
||||
tick_box,
|
||||
info_box,
|
||||
cross_box,
|
||||
mock_command,
|
||||
mock_command_2,
|
||||
run_script
|
||||
)
|
||||
|
||||
|
||||
def test_supported_operating_system(Pihole):
|
||||
'''
|
||||
confirm installer exists on unsupported distribution
|
||||
'''
|
||||
# break supported package managers to emulate an unsupported distribution
|
||||
Pihole.run('rm -rf /usr/bin/apt-get')
|
||||
Pihole.run('rm -rf /usr/bin/rpm')
|
||||
distro_check = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
''')
|
||||
expected_stdout = cross_box + ' OS distribution not supported'
|
||||
assert expected_stdout in distro_check.stdout
|
||||
# assert distro_check.rc == 1
|
||||
|
||||
|
||||
def test_setupVars_are_sourced_to_global_scope(Pihole):
|
||||
'''
|
||||
currently update_dialogs sources setupVars with a dot,
|
||||
then various other functions use the variables.
|
||||
This confirms the sourced variables are in scope between functions
|
||||
'''
|
||||
setup_var_file = 'cat <<EOF> /etc/pihole/setupVars.conf\n'
|
||||
for k, v in SETUPVARS.items():
|
||||
setup_var_file += "{}={}\n".format(k, v)
|
||||
setup_var_file += "EOF\n"
|
||||
Pihole.run(setup_var_file)
|
||||
|
||||
script = dedent('''\
|
||||
set -e
|
||||
printSetupVars() {
|
||||
# Currently debug test function only
|
||||
echo "Outputting sourced variables"
|
||||
echo "PIHOLE_INTERFACE=${PIHOLE_INTERFACE}"
|
||||
echo "IPV4_ADDRESS=${IPV4_ADDRESS}"
|
||||
echo "IPV6_ADDRESS=${IPV6_ADDRESS}"
|
||||
echo "PIHOLE_DNS_1=${PIHOLE_DNS_1}"
|
||||
echo "PIHOLE_DNS_2=${PIHOLE_DNS_2}"
|
||||
}
|
||||
update_dialogs() {
|
||||
. /etc/pihole/setupVars.conf
|
||||
}
|
||||
update_dialogs
|
||||
printSetupVars
|
||||
''')
|
||||
|
||||
output = run_script(Pihole, script).stdout
|
||||
|
||||
for k, v in SETUPVARS.items():
|
||||
assert "{}={}".format(k, v) in output
|
||||
|
||||
|
||||
def test_setupVars_saved_to_file(Pihole):
|
||||
'''
|
||||
confirm saved settings are written to a file for future updates to re-use
|
||||
'''
|
||||
# dedent works better with this and padding matching script below
|
||||
set_setup_vars = '\n'
|
||||
for k, v in SETUPVARS.items():
|
||||
set_setup_vars += " {}={}\n".format(k, v)
|
||||
Pihole.run(set_setup_vars).stdout
|
||||
|
||||
script = dedent('''\
|
||||
set -e
|
||||
echo start
|
||||
TERM=xterm
|
||||
source /opt/pihole/basic-install.sh
|
||||
{}
|
||||
mkdir -p /etc/dnsmasq.d
|
||||
version_check_dnsmasq
|
||||
echo "" > /etc/pihole/pihole-FTL.conf
|
||||
finalExports
|
||||
cat /etc/pihole/setupVars.conf
|
||||
'''.format(set_setup_vars))
|
||||
|
||||
output = run_script(Pihole, script).stdout
|
||||
|
||||
for k, v in SETUPVARS.items():
|
||||
assert "{}={}".format(k, v) in output
|
||||
|
||||
|
||||
def test_selinux_not_detected(Pihole):
|
||||
'''
|
||||
confirms installer continues when SELinux configuration file does not exist
|
||||
'''
|
||||
check_selinux = Pihole.run('''
|
||||
rm -f /etc/selinux/config
|
||||
source /opt/pihole/basic-install.sh
|
||||
checkSelinux
|
||||
''')
|
||||
expected_stdout = info_box + ' SELinux not detected'
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
assert check_selinux.rc == 0
|
||||
|
||||
|
||||
def test_installPiholeWeb_fresh_install_no_errors(Pihole):
|
||||
'''
|
||||
confirms all web page assets from Core repo are installed on a fresh build
|
||||
'''
|
||||
installWeb = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
installPiholeWeb
|
||||
''')
|
||||
expected_stdout = info_box + ' Installing blocking page...'
|
||||
assert expected_stdout in installWeb.stdout
|
||||
expected_stdout = tick_box + (' Creating directory for blocking page, '
|
||||
'and copying files')
|
||||
assert expected_stdout in installWeb.stdout
|
||||
expected_stdout = info_box + ' Backing up index.lighttpd.html'
|
||||
assert expected_stdout in installWeb.stdout
|
||||
expected_stdout = ('No default index.lighttpd.html file found... '
|
||||
'not backing up')
|
||||
assert expected_stdout in installWeb.stdout
|
||||
expected_stdout = tick_box + ' Installing sudoer file'
|
||||
assert expected_stdout in installWeb.stdout
|
||||
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
|
||||
assert 'index.php' in web_directory
|
||||
assert 'blockingpage.css' in web_directory
|
||||
|
||||
|
||||
def test_update_package_cache_success_no_errors(Pihole):
|
||||
'''
|
||||
confirms package cache was updated without any errors
|
||||
'''
|
||||
updateCache = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
update_package_cache
|
||||
''')
|
||||
expected_stdout = tick_box + ' Update local cache of available packages'
|
||||
assert expected_stdout in updateCache.stdout
|
||||
assert 'error' not in updateCache.stdout.lower()
|
||||
|
||||
|
||||
def test_update_package_cache_failure_no_errors(Pihole):
|
||||
'''
|
||||
confirms package cache was not updated
|
||||
'''
|
||||
mock_command('apt-get', {'update': ('', '1')}, Pihole)
|
||||
updateCache = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
update_package_cache
|
||||
''')
|
||||
expected_stdout = cross_box + ' Update local cache of available packages'
|
||||
assert expected_stdout in updateCache.stdout
|
||||
assert 'Error: Unable to update package cache.' in updateCache.stdout
|
||||
|
||||
|
||||
def test_FTL_detect_aarch64_no_errors(Pihole):
|
||||
'''
|
||||
confirms only aarch64 package is downloaded for FTL engine
|
||||
'''
|
||||
# mock uname to return aarch64 platform
|
||||
mock_command('uname', {'-m': ('aarch64', '0')}, Pihole)
|
||||
# mock ldd to respond with aarch64 shared library
|
||||
mock_command(
|
||||
'ldd',
|
||||
{
|
||||
'/bin/ls': (
|
||||
'/lib/ld-linux-aarch64.so.1',
|
||||
'0'
|
||||
)
|
||||
},
|
||||
Pihole
|
||||
)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
create_pihole_user
|
||||
funcOutput=$(get_binary_name)
|
||||
binary="pihole-FTL${funcOutput##*pihole-FTL}"
|
||||
theRest="${funcOutput%pihole-FTL*}"
|
||||
FTLdetect "${binary}" "${theRest}"
|
||||
''')
|
||||
expected_stdout = info_box + ' FTL Checks...'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
expected_stdout = tick_box + ' Detected ARM-aarch64 architecture'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
|
||||
def test_FTL_detect_armv6l_no_errors(Pihole):
|
||||
'''
|
||||
confirms only armv6l package is downloaded for FTL engine
|
||||
'''
|
||||
# mock uname to return armv6l platform
|
||||
mock_command('uname', {'-m': ('armv6l', '0')}, Pihole)
|
||||
# mock ldd to respond with aarch64 shared library
|
||||
mock_command('ldd', {'/bin/ls': ('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
create_pihole_user
|
||||
funcOutput=$(get_binary_name)
|
||||
binary="pihole-FTL${funcOutput##*pihole-FTL}"
|
||||
theRest="${funcOutput%pihole-FTL*}"
|
||||
FTLdetect "${binary}" "${theRest}"
|
||||
''')
|
||||
expected_stdout = info_box + ' FTL Checks...'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
expected_stdout = tick_box + (' Detected ARM-hf architecture '
|
||||
'(armv6 or lower)')
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
|
||||
def test_FTL_detect_armv7l_no_errors(Pihole):
|
||||
'''
|
||||
confirms only armv7l package is downloaded for FTL engine
|
||||
'''
|
||||
# mock uname to return armv7l platform
|
||||
mock_command('uname', {'-m': ('armv7l', '0')}, Pihole)
|
||||
# mock ldd to respond with aarch64 shared library
|
||||
mock_command('ldd', {'/bin/ls': ('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
create_pihole_user
|
||||
funcOutput=$(get_binary_name)
|
||||
binary="pihole-FTL${funcOutput##*pihole-FTL}"
|
||||
theRest="${funcOutput%pihole-FTL*}"
|
||||
FTLdetect "${binary}" "${theRest}"
|
||||
''')
|
||||
expected_stdout = info_box + ' FTL Checks...'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
expected_stdout = tick_box + ' Detected ARM-hf architecture (armv7+)'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
|
||||
def test_FTL_detect_x86_64_no_errors(Pihole):
|
||||
'''
|
||||
confirms only x86_64 package is downloaded for FTL engine
|
||||
'''
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
create_pihole_user
|
||||
funcOutput=$(get_binary_name)
|
||||
binary="pihole-FTL${funcOutput##*pihole-FTL}"
|
||||
theRest="${funcOutput%pihole-FTL*}"
|
||||
FTLdetect "${binary}" "${theRest}"
|
||||
''')
|
||||
expected_stdout = info_box + ' FTL Checks...'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
expected_stdout = tick_box + ' Detected x86_64 architecture'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
|
||||
def test_FTL_detect_unknown_no_errors(Pihole):
|
||||
''' confirms only generic package is downloaded for FTL engine '''
|
||||
# mock uname to return generic platform
|
||||
mock_command('uname', {'-m': ('mips', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
create_pihole_user
|
||||
funcOutput=$(get_binary_name)
|
||||
binary="pihole-FTL${funcOutput##*pihole-FTL}"
|
||||
theRest="${funcOutput%pihole-FTL*}"
|
||||
FTLdetect "${binary}" "${theRest}"
|
||||
''')
|
||||
expected_stdout = 'Not able to detect architecture (unknown: mips)'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
|
||||
def test_FTL_download_aarch64_no_errors(Pihole):
|
||||
'''
|
||||
confirms only aarch64 package is downloaded for FTL engine
|
||||
'''
|
||||
# mock whiptail answers and ensure installer dependencies
|
||||
mock_command('whiptail', {'*': ('', '0')}, Pihole)
|
||||
Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
install_dependent_packages ${INSTALLER_DEPS[@]}
|
||||
''')
|
||||
download_binary = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
create_pihole_user
|
||||
FTLinstall "pihole-FTL-aarch64-linux-gnu"
|
||||
''')
|
||||
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
||||
assert expected_stdout in download_binary.stdout
|
||||
assert 'error' not in download_binary.stdout.lower()
|
||||
|
||||
|
||||
def test_FTL_binary_installed_and_responsive_no_errors(Pihole):
|
||||
'''
|
||||
confirms FTL binary is copied and functional in installed location
|
||||
'''
|
||||
installed_binary = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
create_pihole_user
|
||||
funcOutput=$(get_binary_name)
|
||||
binary="pihole-FTL${funcOutput##*pihole-FTL}"
|
||||
theRest="${funcOutput%pihole-FTL*}"
|
||||
FTLdetect "${binary}" "${theRest}"
|
||||
pihole-FTL version
|
||||
''')
|
||||
expected_stdout = 'v'
|
||||
assert expected_stdout in installed_binary.stdout
|
||||
|
||||
|
||||
# def test_FTL_support_files_installed(Pihole):
|
||||
# '''
|
||||
# confirms FTL support files are installed
|
||||
# '''
|
||||
# support_files = Pihole.run('''
|
||||
# source /opt/pihole/basic-install.sh
|
||||
# FTLdetect
|
||||
# stat -c '%a %n' /var/log/pihole-FTL.log
|
||||
# stat -c '%a %n' /run/pihole-FTL.port
|
||||
# stat -c '%a %n' /run/pihole-FTL.pid
|
||||
# ls -lac /run
|
||||
# ''')
|
||||
# assert '644 /run/pihole-FTL.port' in support_files.stdout
|
||||
# assert '644 /run/pihole-FTL.pid' in support_files.stdout
|
||||
# assert '644 /var/log/pihole-FTL.log' in support_files.stdout
|
||||
|
||||
|
||||
def test_IPv6_only_link_local(Pihole):
|
||||
'''
|
||||
confirms IPv6 blocking is disabled for Link-local address
|
||||
'''
|
||||
# mock ip -6 address to return Link-local address
|
||||
mock_command_2(
|
||||
'ip',
|
||||
{
|
||||
'-6 address': (
|
||||
'inet6 fe80::d210:52fa:fe00:7ad7/64 scope link',
|
||||
'0'
|
||||
)
|
||||
},
|
||||
Pihole
|
||||
)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
useIPv6dialog
|
||||
''')
|
||||
expected_stdout = ('Unable to find IPv6 ULA/GUA address, '
|
||||
'IPv6 adblocking will not be enabled')
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
|
||||
def test_IPv6_only_ULA(Pihole):
|
||||
'''
|
||||
confirms IPv6 blocking is enabled for ULA addresses
|
||||
'''
|
||||
# mock ip -6 address to return ULA address
|
||||
mock_command_2(
|
||||
'ip',
|
||||
{
|
||||
'-6 address': (
|
||||
'inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global',
|
||||
'0'
|
||||
)
|
||||
},
|
||||
Pihole
|
||||
)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
useIPv6dialog
|
||||
''')
|
||||
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
|
||||
def test_IPv6_only_GUA(Pihole):
|
||||
'''
|
||||
confirms IPv6 blocking is enabled for GUA addresses
|
||||
'''
|
||||
# mock ip -6 address to return GUA address
|
||||
mock_command_2(
|
||||
'ip',
|
||||
{
|
||||
'-6 address': (
|
||||
'inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global',
|
||||
'0'
|
||||
)
|
||||
},
|
||||
Pihole
|
||||
)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
useIPv6dialog
|
||||
''')
|
||||
expected_stdout = 'Found IPv6 GUA address, using it for blocking IPv6 ads'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
|
||||
def test_IPv6_GUA_ULA_test(Pihole):
|
||||
'''
|
||||
confirms IPv6 blocking is enabled for GUA and ULA addresses
|
||||
'''
|
||||
# mock ip -6 address to return GUA and ULA addresses
|
||||
mock_command_2(
|
||||
'ip',
|
||||
{
|
||||
'-6 address': (
|
||||
'inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global\n'
|
||||
'inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global',
|
||||
'0'
|
||||
)
|
||||
},
|
||||
Pihole
|
||||
)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
useIPv6dialog
|
||||
''')
|
||||
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
|
||||
def test_IPv6_ULA_GUA_test(Pihole):
|
||||
'''
|
||||
confirms IPv6 blocking is enabled for GUA and ULA addresses
|
||||
'''
|
||||
# mock ip -6 address to return ULA and GUA addresses
|
||||
mock_command_2(
|
||||
'ip',
|
||||
{
|
||||
'-6 address': (
|
||||
'inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global\n'
|
||||
'inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global',
|
||||
'0'
|
||||
)
|
||||
},
|
||||
Pihole
|
||||
)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
useIPv6dialog
|
||||
''')
|
||||
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
|
||||
def test_validate_ip_valid(Pihole):
|
||||
'''
|
||||
Given a valid IP address, valid_ip returns success
|
||||
'''
|
||||
|
||||
output = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
valid_ip "192.168.1.1"
|
||||
''')
|
||||
|
||||
assert output.rc == 0
|
||||
|
||||
|
||||
def test_validate_ip_invalid_octet(Pihole):
|
||||
'''
|
||||
Given an invalid IP address (large octet), valid_ip returns an error
|
||||
'''
|
||||
|
||||
output = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
valid_ip "1092.168.1.1"
|
||||
''')
|
||||
|
||||
assert output.rc == 1
|
||||
|
||||
|
||||
def test_validate_ip_invalid_letters(Pihole):
|
||||
'''
|
||||
Given an invalid IP address (contains letters), valid_ip returns an error
|
||||
'''
|
||||
|
||||
output = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
valid_ip "not an IP"
|
||||
''')
|
||||
|
||||
assert output.rc == 1
|
@@ -1,63 +0,0 @@
|
||||
from .conftest import (
|
||||
tick_box,
|
||||
info_box,
|
||||
mock_command,
|
||||
)
|
||||
|
||||
|
||||
def test_php_upgrade_default_optout_centos_eq_7(host):
|
||||
'''
|
||||
confirms the default behavior to opt-out of installing PHP7 from REMI
|
||||
'''
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_upgrade_user_optout_centos_eq_7(host):
|
||||
'''
|
||||
confirms installer behavior when user opt-out of installing PHP7 from REMI
|
||||
(php not currently installed)
|
||||
'''
|
||||
# Whiptail dialog returns Cancel for user prompt
|
||||
mock_command('whiptail', {'*': ('', '1')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_upgrade_user_optin_centos_eq_7(host):
|
||||
'''
|
||||
confirms installer behavior when user opt-in to installing PHP7 from REMI
|
||||
(php not currently installed)
|
||||
'''
|
||||
# Whiptail dialog returns Continue for user prompt
|
||||
mock_command('whiptail', {'*': ('', '0')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
assert 'opt-out' not in package_manager_detect.stdout
|
||||
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||
'(https://rpms.remirepo.net)')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||
'been enabled for PHP7')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert remi_package.is_installed
|
@@ -1,68 +0,0 @@
|
||||
from .conftest import (
|
||||
tick_box,
|
||||
info_box,
|
||||
mock_command,
|
||||
)
|
||||
|
||||
|
||||
def test_php_upgrade_default_continue_centos_gte_8(host):
|
||||
'''
|
||||
confirms the latest version of CentOS continues / does not optout
|
||||
(should trigger on CentOS7 only)
|
||||
'''
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.'
|
||||
' Deprecated PHP may be in use.')
|
||||
assert unexpected_stdout not in package_manager_detect.stdout
|
||||
# ensure remi was not installed on latest CentOS
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_upgrade_user_optout_skipped_centos_gte_8(host):
|
||||
'''
|
||||
confirms installer skips user opt-out of installing PHP7 from REMI on
|
||||
latest CentOS (should trigger on CentOS7 only)
|
||||
(php not currently installed)
|
||||
'''
|
||||
# Whiptail dialog returns Cancel for user prompt
|
||||
mock_command('whiptail', {'*': ('', '1')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.'
|
||||
' Deprecated PHP may be in use.')
|
||||
assert unexpected_stdout not in package_manager_detect.stdout
|
||||
# ensure remi was not installed on latest CentOS
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_upgrade_user_optin_skipped_centos_gte_8(host):
|
||||
'''
|
||||
confirms installer skips user opt-in to installing PHP7 from REMI on
|
||||
latest CentOS (should trigger on CentOS7 only)
|
||||
(php not currently installed)
|
||||
'''
|
||||
# Whiptail dialog returns Continue for user prompt
|
||||
mock_command('whiptail', {'*': ('', '0')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
assert 'opt-out' not in package_manager_detect.stdout
|
||||
unexpected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||
'(https://rpms.remirepo.net)')
|
||||
assert unexpected_stdout not in package_manager_detect.stdout
|
||||
unexpected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||
'been enabled for PHP7')
|
||||
assert unexpected_stdout not in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
@@ -1,125 +0,0 @@
|
||||
import pytest
|
||||
from .conftest import (
|
||||
tick_box,
|
||||
info_box,
|
||||
cross_box,
|
||||
mock_command,
|
||||
)
|
||||
|
||||
|
||||
def test_release_supported_version_check_centos(host):
|
||||
'''
|
||||
confirms installer exits on unsupported releases of CentOS
|
||||
'''
|
||||
# modify /etc/redhat-release to mock an unsupported CentOS release
|
||||
host.run('echo "CentOS Linux release 6.9" > /etc/redhat-release')
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = cross_box + (' CentOS 6 is not supported.')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
expected_stdout = 'Please update to CentOS release 7 or later'
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
|
||||
|
||||
def test_enable_epel_repository_centos(host):
|
||||
'''
|
||||
confirms the EPEL package repository is enabled when installed on CentOS
|
||||
'''
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = info_box + (' Enabling EPEL package repository '
|
||||
'(https://fedoraproject.org/wiki/EPEL)')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
expected_stdout = tick_box + ' Installed epel-release'
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
epel_package = host.package('epel-release')
|
||||
assert epel_package.is_installed
|
||||
|
||||
|
||||
def test_php_version_lt_7_detected_upgrade_default_optout_centos(host):
|
||||
'''
|
||||
confirms the default behavior to opt-out of upgrading to PHP7 from REMI
|
||||
'''
|
||||
# first we will install the default php version to test installer behavior
|
||||
php_install = host.run('yum install -y php')
|
||||
assert php_install.rc == 0
|
||||
php_package = host.package('php')
|
||||
default_centos_php_version = php_package.version.split('.')[0]
|
||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_version_lt_7_detected_upgrade_user_optout_centos(host):
|
||||
'''
|
||||
confirms installer behavior when user opt-out to upgrade to PHP7 via REMI
|
||||
'''
|
||||
# first we will install the default php version to test installer behavior
|
||||
php_install = host.run('yum install -y php')
|
||||
assert php_install.rc == 0
|
||||
php_package = host.package('php')
|
||||
default_centos_php_version = php_package.version.split('.')[0]
|
||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||
# Whiptail dialog returns Cancel for user prompt
|
||||
mock_command('whiptail', {'*': ('', '1')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_version_lt_7_detected_upgrade_user_optin_centos(host):
|
||||
'''
|
||||
confirms installer behavior when user opt-in to upgrade to PHP7 via REMI
|
||||
'''
|
||||
# first we will install the default php version to test installer behavior
|
||||
php_install = host.run('yum install -y php')
|
||||
assert php_install.rc == 0
|
||||
php_package = host.package('php')
|
||||
default_centos_php_version = php_package.version.split('.')[0]
|
||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||
# Whiptail dialog returns Continue for user prompt
|
||||
mock_command('whiptail', {'*': ('', '0')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
install_dependent_packages PIHOLE_WEB_DEPS[@]
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout not in package_manager_detect.stdout
|
||||
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||
'(https://rpms.remirepo.net)')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||
'been enabled for PHP7')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert remi_package.is_installed
|
||||
updated_php_package = host.package('php')
|
||||
updated_php_version = updated_php_package.version.split('.')[0]
|
||||
assert int(updated_php_version) == 7
|
@@ -1,65 +0,0 @@
|
||||
from .conftest import (
|
||||
tick_box,
|
||||
cross_box,
|
||||
mock_command,
|
||||
)
|
||||
|
||||
|
||||
def mock_selinux_config(state, host):
|
||||
'''
|
||||
Creates a mock SELinux config file with expected content
|
||||
'''
|
||||
# validate state string
|
||||
valid_states = ['enforcing', 'permissive', 'disabled']
|
||||
assert state in valid_states
|
||||
# getenforce returns the running state of SELinux
|
||||
mock_command('getenforce', {'*': (state.capitalize(), '0')}, host)
|
||||
# create mock configuration with desired content
|
||||
host.run('''
|
||||
mkdir /etc/selinux
|
||||
echo "SELINUX={state}" > /etc/selinux/config
|
||||
'''.format(state=state.lower()))
|
||||
|
||||
|
||||
def test_selinux_enforcing_exit(host):
|
||||
'''
|
||||
confirms installer prompts to exit when SELinux is Enforcing by default
|
||||
'''
|
||||
mock_selinux_config("enforcing", host)
|
||||
check_selinux = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
checkSelinux
|
||||
''')
|
||||
expected_stdout = cross_box + ' Current SELinux: Enforcing'
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
expected_stdout = 'SELinux Enforcing detected, exiting installer'
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
assert check_selinux.rc == 1
|
||||
|
||||
|
||||
def test_selinux_permissive(host):
|
||||
'''
|
||||
confirms installer continues when SELinux is Permissive
|
||||
'''
|
||||
mock_selinux_config("permissive", host)
|
||||
check_selinux = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
checkSelinux
|
||||
''')
|
||||
expected_stdout = tick_box + ' Current SELinux: Permissive'
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
assert check_selinux.rc == 0
|
||||
|
||||
|
||||
def test_selinux_disabled(host):
|
||||
'''
|
||||
confirms installer continues when SELinux is Disabled
|
||||
'''
|
||||
mock_selinux_config("disabled", host)
|
||||
check_selinux = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
checkSelinux
|
||||
''')
|
||||
expected_stdout = tick_box + ' Current SELinux: Disabled'
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
assert check_selinux.rc == 0
|
264
test/test_centos_fedora_support.py
Normal file
264
test/test_centos_fedora_support.py
Normal file
@@ -0,0 +1,264 @@
|
||||
import pytest
|
||||
from .conftest import (
|
||||
tick_box,
|
||||
info_box,
|
||||
cross_box,
|
||||
mock_command,
|
||||
)
|
||||
|
||||
|
||||
def mock_selinux_config(state, Pihole):
|
||||
'''
|
||||
Creates a mock SELinux config file with expected content
|
||||
'''
|
||||
# validate state string
|
||||
valid_states = ['enforcing', 'permissive', 'disabled']
|
||||
assert state in valid_states
|
||||
# getenforce returns the running state of SELinux
|
||||
mock_command('getenforce', {'*': (state.capitalize(), '0')}, Pihole)
|
||||
# create mock configuration with desired content
|
||||
Pihole.run('''
|
||||
mkdir /etc/selinux
|
||||
echo "SELINUX={state}" > /etc/selinux/config
|
||||
'''.format(state=state.lower()))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('centos'), ('fedora'), ])
|
||||
def test_selinux_enforcing_exit(Pihole):
|
||||
'''
|
||||
confirms installer prompts to exit when SELinux is Enforcing by default
|
||||
'''
|
||||
mock_selinux_config("enforcing", Pihole)
|
||||
check_selinux = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
checkSelinux
|
||||
''')
|
||||
expected_stdout = cross_box + ' Current SELinux: Enforcing'
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
expected_stdout = 'SELinux Enforcing detected, exiting installer'
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
assert check_selinux.rc == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('centos'), ('fedora'), ])
|
||||
def test_selinux_permissive(Pihole):
|
||||
'''
|
||||
confirms installer continues when SELinux is Permissive
|
||||
'''
|
||||
mock_selinux_config("permissive", Pihole)
|
||||
check_selinux = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
checkSelinux
|
||||
''')
|
||||
expected_stdout = tick_box + ' Current SELinux: Permissive'
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
assert check_selinux.rc == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('centos'), ('fedora'), ])
|
||||
def test_selinux_disabled(Pihole):
|
||||
'''
|
||||
confirms installer continues when SELinux is Disabled
|
||||
'''
|
||||
mock_selinux_config("disabled", Pihole)
|
||||
check_selinux = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
checkSelinux
|
||||
''')
|
||||
expected_stdout = tick_box + ' Current SELinux: Disabled'
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
assert check_selinux.rc == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('fedora'), ])
|
||||
def test_epel_and_remi_not_installed_fedora(Pihole):
|
||||
'''
|
||||
confirms installer does not attempt to install EPEL/REMI repositories
|
||||
on Fedora
|
||||
'''
|
||||
distro_check = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
''')
|
||||
assert distro_check.stdout == ''
|
||||
|
||||
epel_package = Pihole.package('epel-release')
|
||||
assert not epel_package.is_installed
|
||||
remi_package = Pihole.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||
def test_release_supported_version_check_centos(Pihole):
|
||||
'''
|
||||
confirms installer exits on unsupported releases of CentOS
|
||||
'''
|
||||
# modify /etc/redhat-release to mock an unsupported CentOS release
|
||||
Pihole.run('echo "CentOS Linux release 6.9" > /etc/redhat-release')
|
||||
distro_check = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
''')
|
||||
expected_stdout = cross_box + (' CentOS 6 is not supported.')
|
||||
assert expected_stdout in distro_check.stdout
|
||||
expected_stdout = 'Please update to CentOS release 7 or later'
|
||||
assert expected_stdout in distro_check.stdout
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||
def test_enable_epel_repository_centos(Pihole):
|
||||
'''
|
||||
confirms the EPEL package repository is enabled when installed on CentOS
|
||||
'''
|
||||
distro_check = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
''')
|
||||
expected_stdout = info_box + (' Enabling EPEL package repository '
|
||||
'(https://fedoraproject.org/wiki/EPEL)')
|
||||
assert expected_stdout in distro_check.stdout
|
||||
expected_stdout = tick_box + ' Installed epel-release'
|
||||
assert expected_stdout in distro_check.stdout
|
||||
epel_package = Pihole.package('epel-release')
|
||||
assert epel_package.is_installed
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||
def test_php_upgrade_default_optout_centos(Pihole):
|
||||
'''
|
||||
confirms the default behavior to opt-out of installing PHP7 from REMI
|
||||
'''
|
||||
distro_check = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in distro_check.stdout
|
||||
remi_package = Pihole.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||
def test_php_upgrade_user_optout_centos(Pihole):
|
||||
'''
|
||||
confirms installer behavior when user opt-out of installing PHP7 from REMI
|
||||
(php not currently installed)
|
||||
'''
|
||||
# Whiptail dialog returns Cancel for user prompt
|
||||
mock_command('whiptail', {'*': ('', '1')}, Pihole)
|
||||
distro_check = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in distro_check.stdout
|
||||
remi_package = Pihole.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||
def test_php_upgrade_user_optin_centos(Pihole):
|
||||
'''
|
||||
confirms installer behavior when user opt-in to installing PHP7 from REMI
|
||||
(php not currently installed)
|
||||
'''
|
||||
# Whiptail dialog returns Continue for user prompt
|
||||
mock_command('whiptail', {'*': ('', '0')}, Pihole)
|
||||
distro_check = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
''')
|
||||
assert 'opt-out' not in distro_check.stdout
|
||||
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||
'(https://rpms.remirepo.net)')
|
||||
assert expected_stdout in distro_check.stdout
|
||||
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||
'been enabled for PHP7')
|
||||
assert expected_stdout in distro_check.stdout
|
||||
remi_package = Pihole.package('remi-release')
|
||||
assert remi_package.is_installed
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||
def test_php_version_lt_7_detected_upgrade_default_optout_centos(Pihole):
|
||||
'''
|
||||
confirms the default behavior to opt-out of upgrading to PHP7 from REMI
|
||||
'''
|
||||
# first we will install the default php version to test installer behavior
|
||||
php_install = Pihole.run('yum install -y php')
|
||||
assert php_install.rc == 0
|
||||
php_package = Pihole.package('php')
|
||||
default_centos_php_version = php_package.version.split('.')[0]
|
||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||
distro_check = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in distro_check.stdout
|
||||
remi_package = Pihole.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||
def test_php_version_lt_7_detected_upgrade_user_optout_centos(Pihole):
|
||||
'''
|
||||
confirms installer behavior when user opt-out to upgrade to PHP7 via REMI
|
||||
'''
|
||||
# first we will install the default php version to test installer behavior
|
||||
php_install = Pihole.run('yum install -y php')
|
||||
assert php_install.rc == 0
|
||||
php_package = Pihole.package('php')
|
||||
default_centos_php_version = php_package.version.split('.')[0]
|
||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||
# Whiptail dialog returns Cancel for user prompt
|
||||
mock_command('whiptail', {'*': ('', '1')}, Pihole)
|
||||
distro_check = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in distro_check.stdout
|
||||
remi_package = Pihole.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||
def test_php_version_lt_7_detected_upgrade_user_optin_centos(Pihole):
|
||||
'''
|
||||
confirms installer behavior when user opt-in to upgrade to PHP7 via REMI
|
||||
'''
|
||||
# first we will install the default php version to test installer behavior
|
||||
php_install = Pihole.run('yum install -y php')
|
||||
assert php_install.rc == 0
|
||||
php_package = Pihole.package('php')
|
||||
default_centos_php_version = php_package.version.split('.')[0]
|
||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||
# Whiptail dialog returns Continue for user prompt
|
||||
mock_command('whiptail', {'*': ('', '0')}, Pihole)
|
||||
distro_check = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
install_dependent_packages PIHOLE_WEB_DEPS[@]
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout not in distro_check.stdout
|
||||
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||
'(https://rpms.remirepo.net)')
|
||||
assert expected_stdout in distro_check.stdout
|
||||
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||
'been enabled for PHP7')
|
||||
assert expected_stdout in distro_check.stdout
|
||||
remi_package = Pihole.package('remi-release')
|
||||
assert remi_package.is_installed
|
||||
updated_php_package = Pihole.package('php')
|
||||
updated_php_version = updated_php_package.version.split('.')[0]
|
||||
assert int(updated_php_version) == 7
|
@@ -1,16 +0,0 @@
|
||||
def test_epel_and_remi_not_installed_fedora(host):
|
||||
'''
|
||||
confirms installer does not attempt to install EPEL/REMI repositories
|
||||
on Fedora
|
||||
'''
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
assert package_manager_detect.stdout == ''
|
||||
|
||||
epel_package = host.package('epel-release')
|
||||
assert not epel_package.is_installed
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
18
test/test_shellcheck.py
Normal file
18
test/test_shellcheck.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import testinfra
|
||||
|
||||
run_local = testinfra.get_backend(
|
||||
"local://"
|
||||
).get_module("Command").run
|
||||
|
||||
|
||||
def test_scripts_pass_shellcheck():
|
||||
'''
|
||||
Make sure shellcheck does not find anything wrong with our shell scripts
|
||||
'''
|
||||
shellcheck = ("find . -type f -name 'update.sh' "
|
||||
"| while read file; do "
|
||||
"shellcheck -x \"$file\" -e SC1090,SC1091; "
|
||||
"done;")
|
||||
results = run_local(shellcheck)
|
||||
print(results.stdout)
|
||||
assert '' == results.stdout
|
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _centos_7.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_centos_common_support.py ./test_centos_7_support.py
|
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _centos_8.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_centos_common_support.py ./test_centos_8_support.py
|
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _debian_10.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _debian_11.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _debian_9.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _fedora_33.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_fedora_support.py
|
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _fedora_34.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_fedora_support.py
|
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _ubuntu_16.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _ubuntu_18.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _ubuntu_20.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _ubuntu_21.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
10
tox.ini
Normal file
10
tox.ini
Normal file
@@ -0,0 +1,10 @@
|
||||
[tox]
|
||||
envlist = py36
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f test/debian.Dockerfile -t pytest_pihole:debian .
|
||||
docker build -f test/centos.Dockerfile -t pytest_pihole:centos .
|
||||
docker build -f test/fedora.Dockerfile -t pytest_pihole:fedora .
|
||||
pytest {posargs:-vv -n auto} -m "not build_stage" ./test/
|
Reference in New Issue
Block a user