Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
741c19b975 |
@@ -1,4 +0,0 @@
|
|||||||
doubleclick
|
|
||||||
wan
|
|
||||||
nwe
|
|
||||||
padd
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# EditorConfig is awesome: https://editorconfig.org/
|
# EditorConfig is awesome: http://EditorConfig.org
|
||||||
|
|
||||||
# top-most EditorConfig file
|
# top-most EditorConfig file
|
||||||
root = true
|
root = true
|
||||||
@@ -13,8 +13,26 @@ tab_width = 4
|
|||||||
charset = utf-8
|
charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[*.yml]
|
# Matches multiple files with brace expansion notation
|
||||||
tab_width = 2
|
# Set default charset
|
||||||
|
[*.{js,py}]
|
||||||
|
charset = utf-8
|
||||||
|
|
||||||
[*.md]
|
# 4 space indentation
|
||||||
tab_width = 2
|
[*.py]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
# Tab indentation (no size specified)
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
# Indentation override for all JS under lib directory
|
||||||
|
[scripts/**.js]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# Matches the exact files either package.json or .travis.yml
|
||||||
|
[{package.json,.travis.yml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|||||||
5
.github/CODEOWNERS
vendored
5
.github/CODEOWNERS
vendored
@@ -1,5 +0,0 @@
|
|||||||
# see https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#codeowners-syntax
|
|
||||||
|
|
||||||
# These owners will be the default owners for everything in
|
|
||||||
# the repo. Unless a later match takes precedence,
|
|
||||||
* @pi-hole/core-maintainers
|
|
||||||
37
.github/ISSUE_TEMPLATE.md
vendored
Normal file
37
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
**In raising this issue, I confirm the following:** `{please fill the checkboxes, e.g: [X]}`
|
||||||
|
|
||||||
|
- [] I have read and understood the [contributors guide](https://github.com/pi-hole/pi-hole/blob/master/CONTRIBUTING.md).
|
||||||
|
- [] The issue I am reporting can be *replicated*.
|
||||||
|
- [] The issue I am reporting isn't a duplicate (see [FAQs](https://github.com/pi-hole/pi-hole/wiki/FAQs), [closed issues](https://github.com/pi-hole/pi-hole/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), and [open issues](https://github.com/pi-hole/pi-hole/issues)).
|
||||||
|
|
||||||
|
**How familiar are you with the the source code relevant to this issue?:**
|
||||||
|
|
||||||
|
`{Replace this with a number from 1 to 10. 1 being not familiar, and 10 being very familiar}`
|
||||||
|
|
||||||
|
---
|
||||||
|
**Expected behaviour:**
|
||||||
|
|
||||||
|
`{A detailed description of what you expect to see}`
|
||||||
|
|
||||||
|
**Actual behaviour:**
|
||||||
|
|
||||||
|
`{A detailed description and/or screenshots of what you do see}`
|
||||||
|
|
||||||
|
**Steps to reproduce:**
|
||||||
|
|
||||||
|
`{Detailed steps of how we can reproduce this}`
|
||||||
|
|
||||||
|
**Debug token provided by [uploading `pihole -d` log](https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#debug):**
|
||||||
|
|
||||||
|
`{Alphanumeric token}`
|
||||||
|
|
||||||
|
**Troubleshooting undertaken, and/or other relevant information:**
|
||||||
|
|
||||||
|
`{Steps of what you have done to fix this}`
|
||||||
|
|
||||||
|
> * `{Please delete this quoted section when opening your issue}`
|
||||||
|
> * You must follow the template instructions. Failure to do so will result in your issue being closed.
|
||||||
|
> * Please [submit any feature requests here](https://discourse.pi-hole.net/c/feature-requests), so it is votable and trackable by the community.
|
||||||
|
> * Please respect that Pi-hole is developed by volunteers, who can only reply in their spare time.
|
||||||
|
> * Detail helps us understand and resolve an issue quicker, but please ensure it's relevant.
|
||||||
|
> * _This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._
|
||||||
31
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
31
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
**By submitting this pull request, I confirm the following:**
|
||||||
|
*please fill any appropriate checkboxes, e.g: [X]*
|
||||||
|
|
||||||
|
- [ ] I have read and understood the [contributors guide](https://github.com/pi-hole/pi-hole/blob/master/CONTRIBUTING.md), as well as this entire template.
|
||||||
|
- [ ] I have made only one major change in my proposed changes.
|
||||||
|
- [ ] I have commented my proposed changes within the code.
|
||||||
|
- [ ] I have tested my proposed changes, and have included unit tests where possible.
|
||||||
|
- [ ] I am willing to help maintain this change if there are issues with it later.
|
||||||
|
- [ ] I give this submission freely and claim no ownership.
|
||||||
|
- [ ] It is compatible with the [EUPL 1.2 license](https://opensource.org/licenses/EUPL-1.1)
|
||||||
|
- [ ] I have squashed any insignificant commits. ([`git rebase`](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html))
|
||||||
|
|
||||||
|
Please make sure you [Sign Off](https://github.com/pi-hole/pi-hole/wiki/How-to-signoff-your-commits.) all commits. Pi-hole enforces the [DCO](https://github.com/pi-hole/pi-hole/wiki/Contributing-to-the-project).
|
||||||
|
|
||||||
|
---
|
||||||
|
**What does this PR aim to accomplish?:**
|
||||||
|
*A detailed description, screenshots (if necessary), as well as links to any relevant GitHub issues*
|
||||||
|
|
||||||
|
|
||||||
|
**How does this PR accomplish the above?:**
|
||||||
|
*A detailed description (such as a changelog) and screenshots (if necessary) of the implemented fix*
|
||||||
|
|
||||||
|
|
||||||
|
**What documentation changes (if any) are needed to support this PR?:**
|
||||||
|
*A detailed list of any necessary changes*
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
* You must follow the template instructions. Failure to do so will result in your pull request being closed.
|
||||||
|
* Please respect that Pi-hole is developed by volunteers, who can only reply in their spare time.
|
||||||
|
|
||||||
26
.github/dependabot.yml
vendored
26
.github/dependabot.yml
vendored
@@ -1,26 +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: development
|
|
||||||
groups:
|
|
||||||
github-actions-dependencies:
|
|
||||||
patterns:
|
|
||||||
- "*"
|
|
||||||
- package-ecosystem: pip
|
|
||||||
directory: "/test"
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
day: saturday
|
|
||||||
time: "10:00"
|
|
||||||
open-pull-requests-limit: 10
|
|
||||||
target-branch: development
|
|
||||||
groups:
|
|
||||||
python-dependencies:
|
|
||||||
patterns:
|
|
||||||
- "*"
|
|
||||||
8
.github/release.yml
vendored
8
.github/release.yml
vendored
@@ -1,8 +0,0 @@
|
|||||||
changelog:
|
|
||||||
exclude:
|
|
||||||
labels:
|
|
||||||
- internal
|
|
||||||
- dependencies
|
|
||||||
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
-
|
|
||||||
name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 #v4.32.6
|
|
||||||
with:
|
|
||||||
languages: 'python'
|
|
||||||
-
|
|
||||||
name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@0d579ffd059c29b07949a3cce3983f0780820c98 #v4.32.6
|
|
||||||
-
|
|
||||||
name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 #v4.32.6
|
|
||||||
21
.github/workflows/merge-conflict.yml
vendored
21
.github/workflows/merge-conflict.yml
vendored
@@ -1,21 +0,0 @@
|
|||||||
name: "Check for merge conflicts"
|
|
||||||
on:
|
|
||||||
# So that PRs touching the same files as the push are updated
|
|
||||||
push:
|
|
||||||
# So that the `dirtyLabel` is removed if conflicts are resolve
|
|
||||||
# We recommend `pull_request_target` so that github secrets are available.
|
|
||||||
# In `pull_request` we wouldn't be able to change labels of fork PRs
|
|
||||||
pull_request_target:
|
|
||||||
types: [synchronize]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
main:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Check if PRs are have merge conflicts
|
|
||||||
uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 #v3.0.3
|
|
||||||
with:
|
|
||||||
dirtyLabel: "PR: Merge Conflict"
|
|
||||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
|
||||||
commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request."
|
|
||||||
commentOnClean: "Conflicts have been resolved."
|
|
||||||
47
.github/workflows/stale.yml
vendored
47
.github/workflows/stale.yml
vendored
@@ -1,47 +0,0 @@
|
|||||||
name: Mark stale issues
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 8 * * *'
|
|
||||||
workflow_dispatch:
|
|
||||||
issue_comment:
|
|
||||||
|
|
||||||
env:
|
|
||||||
stale_label: stale
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
stale_action:
|
|
||||||
if: github.event_name != 'issue_comment'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f #v10.2.0
|
|
||||||
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: '${{ env.stale_label }}'
|
|
||||||
exempt-issue-labels: 'Internal, Fixed in next release, Bug: Confirmed, Documentation Needed, never-stale'
|
|
||||||
exempt-all-issue-assignees: true
|
|
||||||
operations-per-run: 300
|
|
||||||
close-issue-reason: 'not_planned'
|
|
||||||
|
|
||||||
remove_stale:
|
|
||||||
# trigger "stale" removal immediately when stale issues are commented on
|
|
||||||
# we need to explicitly check that the trigger does not run on comment on a PR as
|
|
||||||
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issue_comment-on-issues-only-or-pull-requests-only
|
|
||||||
if: ${{ !github.event.issue.pull_request && github.event_name != 'schedule' }}
|
|
||||||
permissions:
|
|
||||||
contents: read # for actions/checkout
|
|
||||||
issues: write # to edit issues label
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
|
||||||
- name: Remove 'stale' label
|
|
||||||
run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
35
.github/workflows/stale_pr.yml
vendored
35
.github/workflows/stale_pr.yml
vendored
@@ -1,35 +0,0 @@
|
|||||||
name: Close stale PR
|
|
||||||
# This action will add a `stale` label and close immediately every PR that meets the following conditions:
|
|
||||||
# - it is already marked with "merge conflict" label
|
|
||||||
# - there was no update/comment on the PR in the last 30 days.
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 10 * * *'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
stale:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f #v10.2.0
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
# Do not automatically mark PR/issue as stale
|
|
||||||
days-before-stale: -1
|
|
||||||
# Override 'days-before-stale' for PR only
|
|
||||||
days-before-pr-stale: 30
|
|
||||||
# Close PRs immediately, after marking them 'stale'
|
|
||||||
days-before-pr-close: 0
|
|
||||||
# only run the action on merge conflict PR
|
|
||||||
any-of-labels: 'PR: Merge Conflict'
|
|
||||||
exempt-pr-labels: 'internal, never-stale, ON HOLD, WIP'
|
|
||||||
exempt-all-pr-assignees: true
|
|
||||||
operations-per-run: 300
|
|
||||||
stale-pr-message: ''
|
|
||||||
close-pr-message: 'Existing merge conflicts have not been addressed. This PR is considered abandoned.'
|
|
||||||
40
.github/workflows/sync-back-to-dev.yml
vendored
40
.github/workflows/sync-back-to-dev.yml
vendored
@@ -1,40 +0,0 @@
|
|||||||
name: Sync Back to Development
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
# The section is needed to drop the default write-all permissions for all jobs
|
|
||||||
# that are granted on `push` event. By specifying any permission explicitly
|
|
||||||
# all others are set to none. By using the principle of least privilege the damage a compromised
|
|
||||||
# workflow can do (because of an injection or compromised third party tool or
|
|
||||||
# action) is restricted. Adding labels to issues, commenting
|
|
||||||
# on pull-requests, etc. may need additional permissions:
|
|
||||||
#
|
|
||||||
# Syntax for this section:
|
|
||||||
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
|
||||||
#
|
|
||||||
# Reference for how to assign permissions on a job-by-job basis:
|
|
||||||
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
|
|
||||||
#
|
|
||||||
# Reference for available permissions that we can enable if needed:
|
|
||||||
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
|
|
||||||
permissions: {}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
sync-branches:
|
|
||||||
# The job needs to be able to pull the code and create a pull request.
|
|
||||||
permissions:
|
|
||||||
contents: read # for actions/checkout
|
|
||||||
pull-requests: write # to create pull request
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Syncing branches
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
|
||||||
- name: Opening pull request
|
|
||||||
run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'internal'
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
104
.github/workflows/test.yml
vendored
104
.github/workflows/test.yml
vendored
@@ -1,104 +0,0 @@
|
|||||||
name: Test Supported Distributions
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened, ready_for_review]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
env:
|
|
||||||
FORCE_COLOR: 1
|
|
||||||
PYTHONUNBUFFERED: 1
|
|
||||||
PYTHONUTF8: 1
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
smoke-tests:
|
|
||||||
if: github.event.pull_request.draft == false
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Differential ShellCheck requires full git history
|
|
||||||
|
|
||||||
- name: Check scripts in repository are executable
|
|
||||||
run: |
|
|
||||||
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 "Scripts are executable!"
|
|
||||||
|
|
||||||
- name: Differential ShellCheck
|
|
||||||
uses: redhat-plumbers-in-action/differential-shellcheck@d965e66ec0b3b2f821f75c8eff9b12442d9a7d1e #v5.5.6
|
|
||||||
with:
|
|
||||||
severity: warning
|
|
||||||
display-engine: sarif-fmt
|
|
||||||
|
|
||||||
- name: Secret Scanning with TruffleHog
|
|
||||||
uses: trufflesecurity/trufflehog@821e8b9e5cdf8dc484dd23e06f78941fcf6b9191 #v3.91.2
|
|
||||||
with:
|
|
||||||
extra_args: --results=verified,unknown
|
|
||||||
|
|
||||||
- name: Spell-Checking
|
|
||||||
uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 #v2.2
|
|
||||||
with:
|
|
||||||
ignore_words_file: .codespellignore
|
|
||||||
|
|
||||||
- name: Get editorconfig-checker
|
|
||||||
uses: editorconfig-checker/action-editorconfig-checker@4b6cd6190d435e7e084fb35e36a096e98506f7b9 #v2.1.0
|
|
||||||
|
|
||||||
- name: Run editorconfig-checker
|
|
||||||
run: editorconfig-checker
|
|
||||||
|
|
||||||
- name: Check python code formatting with black
|
|
||||||
uses: psf/black@c6755bb741b6481d6b3d3bb563c83fa060db96c9 #26.3.1
|
|
||||||
with:
|
|
||||||
src: "./test"
|
|
||||||
options: "--check --diff --color"
|
|
||||||
|
|
||||||
distro-test:
|
|
||||||
if: github.event.pull_request.draft == false
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: smoke-tests
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
distro:
|
|
||||||
[
|
|
||||||
debian_11,
|
|
||||||
debian_12,
|
|
||||||
debian_13,
|
|
||||||
ubuntu_20,
|
|
||||||
ubuntu_22,
|
|
||||||
ubuntu_24,
|
|
||||||
centos_9,
|
|
||||||
centos_10,
|
|
||||||
fedora_40,
|
|
||||||
fedora_41,
|
|
||||||
fedora_42,
|
|
||||||
fedora_43,
|
|
||||||
alpine_3_21,
|
|
||||||
alpine_3_22,
|
|
||||||
alpine_3_23,
|
|
||||||
]
|
|
||||||
env:
|
|
||||||
DISTRO: ${{matrix.distro}}
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
|
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 #v6.2.0
|
|
||||||
with:
|
|
||||||
python-version: "3.13"
|
|
||||||
|
|
||||||
- name: Install wheel
|
|
||||||
run: pip install wheel
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pip install -r test/requirements.txt
|
|
||||||
|
|
||||||
- name: Test with tox
|
|
||||||
run: tox -c test/tox.${DISTRO}.ini
|
|
||||||
71
.gitignore
vendored
71
.gitignore
vendored
@@ -7,9 +7,70 @@ __pycache__
|
|||||||
.tox
|
.tox
|
||||||
.eggs
|
.eggs
|
||||||
*.egg-info
|
*.egg-info
|
||||||
.idea/
|
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/jetbrains+iml
|
||||||
|
|
||||||
|
### JetBrains+iml ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# All idea files, with execptions
|
||||||
|
.idea
|
||||||
|
!.idea/codeStyles/*
|
||||||
|
!.idea/codeStyleSettings.xml
|
||||||
|
|
||||||
|
|
||||||
|
# Sensitive or high-churn files:
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.xml
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
|
||||||
|
# Gradle:
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-debug/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin:
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Ruby plugin and RubyMine
|
||||||
|
/.rakeTasks
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
### JetBrains+iml Patch ###
|
||||||
|
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
||||||
|
|
||||||
*.iml
|
*.iml
|
||||||
.vscode/
|
.idea/misc.xml
|
||||||
.venv/
|
*.ipr
|
||||||
.fleet/
|
|
||||||
.cache/
|
# 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>
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
external-sources=true # allow shellcheck to read external sources
|
|
||||||
disable=SC3043 #disable SC3043: In POSIX sh, local is undefined.
|
|
||||||
enable=useless-use-of-cat # disabled by default as of shellcheck 0.11.0
|
|
||||||
enable=avoid-negated-conditions # avoid-negated-conditions is optional as of shellcheck 0.11.0
|
|
||||||
enable=require-variable-braces
|
|
||||||
enable=deprecate-which
|
|
||||||
6
.stickler.yml
Normal file
6
.stickler.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
linters:
|
||||||
|
shellcheck:
|
||||||
|
shell: bash
|
||||||
|
phpcs:
|
||||||
|
csslint:
|
||||||
|
flake8:
|
||||||
12
.travis.yml
Normal file
12
.travis.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
sudo: required
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
language: python
|
||||||
|
python:
|
||||||
|
- "2.7"
|
||||||
|
install:
|
||||||
|
- pip install -r requirements.txt
|
||||||
|
|
||||||
|
script:
|
||||||
|
# tox.ini handles setup, ordering of docker build first, and then run tests
|
||||||
|
- tox
|
||||||
@@ -2,4 +2,37 @@
|
|||||||
|
|
||||||
Please read and understand the contribution guide before creating an issue or pull request.
|
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.
|
||||||
|
|||||||
245
README.md
245
README.md
@@ -1,170 +1,213 @@
|
|||||||
<!-- markdownlint-configure-file { "MD004": { "style": "consistent" } } -->
|
|
||||||
<!-- markdownlint-disable MD033 -->
|
|
||||||
#
|
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://raw.githubusercontent.com/pi-hole/graphics/refs/heads/master/Vortex/vortex_with_text.svg" alt="Pi-hole website" width="168" height="270">
|
<a href="https://pi-hole.net"><img src="https://pi-hole.github.io/graphics/Vortex/Vortex_with_text.png" width="150" height="255" alt="Pi-hole"></a><br/>
|
||||||
<br>
|
<b>Network-wide ad blocking via your own Linux hardware</b><br/>
|
||||||
<strong>Network-wide ad blocking via your own Linux hardware</strong>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- markdownlint-enable MD033 -->
|
The Pi-hole[®](https://pi-hole.net/trademark-rules-and-brand-guidelines/) is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content, without installing any client-side software.
|
||||||
|
|
||||||
The Pi-hole® is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content without installing any client-side software.
|
- **Easy-to-install**: our versatile installer walks you through the process, and [takes less than ten minutes](https://www.youtube.com/watch?v=vKWjx1AQYgs)
|
||||||
|
|
||||||
- **Easy-to-install**: our dialogs walk you through the simple installation process in less than ten minutes
|
|
||||||
- **Resolute**: content is blocked in _non-browser locations_, such as ad-laden mobile apps and smart TVs
|
- **Resolute**: content is blocked in _non-browser locations_, such as ad-laden mobile apps and smart TVs
|
||||||
- **Responsive**: seamlessly speeds up the feel of everyday browsing by caching DNS queries
|
- **Responsive**: seamlessly speeds up the feel of everyday browsing by caching DNS queries
|
||||||
- **Lightweight**: runs smoothly with [minimal hardware and software requirements](https://docs.pi-hole.net/main/prerequisites/)
|
- **Lightweight**: runs smoothly with [minimal hardware and software requirements](https://discourse.pi-hole.net/t/hardware-software-requirements/273)
|
||||||
- **Robust**: a command-line interface that is quality assured for interoperability
|
- **Robust**: a command line interface that is quality assured for interoperability
|
||||||
- **Insightful**: a beautiful responsive Web Interface dashboard to view and control your Pi-hole
|
- **Insightful**: a beautiful responsive Web Interface dashboard to view and control your Pi-hole
|
||||||
- **Versatile**: can optionally function as a [DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026), ensuring _all_ your devices are protected automatically
|
- **Versatile**: can optionally function as a [DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026), ensuring *all* your devices are protected automatically
|
||||||
- **Scalable**: [capable of handling hundreds of millions of queries](https://pi-hole.net/2017/05/24/how-much-traffic-can-pi-hole-handle/) when installed on server-grade hardware
|
- **Scalable**: [capable of handling hundreds of millions of queries](https://pi-hole.net/2017/05/24/how-much-traffic-can-pi-hole-handle/) when installed on server-grade hardware
|
||||||
- **Modern**: blocks ads over both IPv4 and IPv6
|
- **Modern**: blocks ads over both IPv4 and IPv6
|
||||||
- **Free**: open source software 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
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
[](https://www.codacy.com/app/Pi-hole/pi-hole?utm_source=github.com&utm_medium=referral&utm_content=pi-hole/pi-hole&utm_campaign=Badge_Grade)
|
||||||
|
[](https://travis-ci.org/pi-hole/pi-hole)
|
||||||
|
[](https://www.bountysource.com/trackers/3011939-pi-hole-pi-hole?utm_source=3011939&utm_medium=shield&utm_campaign=TRACKER_BADGE)
|
||||||
|
|
||||||
## One-Step Automated Install
|
## One-Step Automated Install
|
||||||
|
|
||||||
Those who want to get started quickly and conveniently may install Pi-hole using the following command:
|
Those who want to get started quickly and conveniently may install Pi-hole using the following command:
|
||||||
|
|
||||||
```bash
|
#### `curl -sSL https://install.pi-hole.net | bash`
|
||||||
curl -sSL https://install.pi-hole.net | bash
|
|
||||||
```
|
|
||||||
|
|
||||||
## Alternative Install Methods
|
## Alternative Install Methods
|
||||||
|
[Piping to `bash` is controversial](https://pi-hole.net/2016/07/25/curling-and-piping-to-bash), as it prevents you from [reading code that is about to run](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) on your system. Therefore, we provide these alternative installation methods which allow code review before installation:
|
||||||
Piping to `bash` is [controversial](https://pi-hole.net/2016/07/25/curling-and-piping-to-bash), as it prevents you from [reading code that is about to run](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) on your system. Therefore, we provide these alternative installation methods which allow code review before installation:
|
|
||||||
|
|
||||||
### Method 1: Clone our repository and run
|
### Method 1: Clone our repository and run
|
||||||
|
```
|
||||||
```bash
|
|
||||||
git clone --depth 1 https://github.com/pi-hole/pi-hole.git Pi-hole
|
git clone --depth 1 https://github.com/pi-hole/pi-hole.git Pi-hole
|
||||||
cd "Pi-hole/automated install/"
|
cd "Pi-hole/automated install/"
|
||||||
sudo bash basic-install.sh
|
sudo bash basic-install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### Method 2: Manually download the installer and run
|
### Method 2: Manually download the installer and run
|
||||||
|
```
|
||||||
```bash
|
|
||||||
wget -O basic-install.sh https://install.pi-hole.net
|
wget -O basic-install.sh https://install.pi-hole.net
|
||||||
sudo bash basic-install.sh
|
sudo bash basic-install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### Method 3: Using Docker to deploy Pi-hole
|
## Post-install: Make your network take advantage of Pi-hole
|
||||||
|
|
||||||
Please refer to the [Pi-hole docker repo](https://github.com/pi-hole/docker-pi-hole) to use the Official Docker Images.
|
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.
|
||||||
|
|
||||||
## [Post-install: Make your network take advantage of Pi-hole](https://docs.pi-hole.net/main/post-install/)
|
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).
|
||||||
|
|
||||||
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). This router configuration will ensure that all devices connecting to your network will have content blocked without any further intervention.
|
As a last resort, you can always manually set each device to use Pi-hole as their DNS server.
|
||||||
|
|
||||||
If your router does not support setting the DNS server, you can [use Pi-hole's built-in DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026); be sure to disable DHCP on your router first (if it has that feature available).
|
|
||||||
|
|
||||||
As a last resort, you can manually set each device to use Pi-hole as their DNS server.
|
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
## Pi-hole is free but powered by your support
|
## Pi-hole is free, but powered by your support
|
||||||
|
There are many reoccurring costs involved with maintaining free, open source, and privacy-respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software, as well as the importance of keeping it maintained.
|
||||||
There are many reoccurring costs involved with maintaining free, open-source, and privacy-respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software and the importance of keeping it maintained.
|
|
||||||
|
|
||||||
Make no mistake: **your support is absolutely vital to help keep us innovating!**
|
Make no mistake: **your support is absolutely vital to help keep us innovating!**
|
||||||
|
|
||||||
### [Donations](https://pi-hole.net/donate)
|
### Donations
|
||||||
|
Sending a donation using our links below is **extremely helpful** in offsetting a portion of our monthly expenses:
|
||||||
|
|
||||||
Donating using our Sponsor Button is **extremely helpful** in offsetting a portion of our monthly expenses:
|
- <img src="https://pi-hole.github.io/graphics/Badges/paypal-badge-black.svg" width="24" height="24" alt="PP"/> <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY">Donate via PayPal</a><br/>
|
||||||
|
- <img src="https://pi-hole.github.io/graphics/Badges/bitcoin-badge-black.svg" width="24" height="24" alt="BTC"/> [Bitcoin, Bitcoin Cash, Ethereum, Litecoin](https://commerce.coinbase.com/checkout/dd304d04-f324-4a77-931b-0db61c77a41b)
|
||||||
|
|
||||||
### Alternative support
|
### Alternative support
|
||||||
|
If you'd rather not [donate](https://pi-hole.net/donate/) (_which is okay!_), there are other ways you can help support us:
|
||||||
If you'd rather not donate (_which is okay!_), there are other ways you can help support us:
|
- [Patreon](https://patreon.com/pihole) _Become a patron for rewards_
|
||||||
|
- [Digital Ocean](http://www.digitalocean.com/?refcode=344d234950e1) _affiliate link_
|
||||||
- [GitHub Sponsors](https://github.com/sponsors/pi-hole/)
|
|
||||||
- [Patreon](https://patreon.com/pihole)
|
|
||||||
- [Hetzner Cloud](https://hetzner.cloud/?ref=7aceisRX3AzA) _affiliate link_
|
|
||||||
- [Digital Ocean](https://www.digitalocean.com/?refcode=344d234950e1) _affiliate link_
|
|
||||||
- [Stickermule](https://www.stickermule.com/unlock?ref_id=9127301701&utm_medium=link&utm_source=invite) _earn a $10 credit after your first purchase_
|
- [Stickermule](https://www.stickermule.com/unlock?ref_id=9127301701&utm_medium=link&utm_source=invite) _earn a $10 credit after your first purchase_
|
||||||
- [Amazon US](https://www.amazon.com/exec/obidos/redirect-home/pihole09-20) _affiliate link_
|
- [Pi-hole Swag Store](https://pi-hole.net/shop/) _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_
|
||||||
|
- [DNS Made Easy](https://cp.dnsmadeeasy.com/u/133706) _affiliate link_
|
||||||
|
- [Vultr](http://www.vultr.com/?ref=7190426) _affiliate link_
|
||||||
|
- Spreading the word about our software, and how you have benefited from it
|
||||||
|
|
||||||
### Contributing via GitHub
|
### Contributing via GitHub
|
||||||
|
|
||||||
We welcome _everyone_ to contribute to issue reports, suggest new features, and create pull requests.
|
We welcome _everyone_ to contribute to issue reports, suggest new features, and create pull requests.
|
||||||
|
|
||||||
If you have something to add - anything from a typo through to a whole new feature, we're happy to check it out! Just make sure to fill out our template when submitting your request; the questions 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.
|
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.
|
||||||
|
|
||||||
|
### Presentations about Pi-hole
|
||||||
|
Word-of-mouth continues to help our project grow immensely, and so we are helping make this easier for people.
|
||||||
|
|
||||||
|
If you are going to be presenting Pi-hole at a conference, meetup or even a school project, [get in touch with us](https://pi-hole.net/2017/05/17/giving-a-presentation-on-pi-hole-contact-us-first-for-some-goodies-and-support/) so we can hook you up with free swag to hand out to your audience!
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
## Getting in touch with us
|
## Getting in touch with us
|
||||||
|
While we are primarily reachable on our <a href="https://discourse.pi-hole.net/">Discourse User Forum</a>, 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.
|
||||||
|
|
||||||
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.
|
<ul>
|
||||||
|
<li><a href="https://discourse.pi-hole.net/c/faqs">Frequently Asked Questions</a></li>
|
||||||
**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.
|
<li><a href="https://github.com/pi-hole/pi-hole/wiki">Pi-hole Wiki</a></li>
|
||||||
|
<li><a href="https://discourse.pi-hole.net/c/feature-requests?order=votes">Feature Requests</a></li>
|
||||||
- [Frequently Asked Questions](https://discourse.pi-hole.net/c/faqs)
|
<li><a href="https://discourse.pi-hole.net/">Discourse User Forum</a></li>
|
||||||
- [Feature Requests](https://discourse.pi-hole.net/c/feature-requests?order=votes)
|
<li><a href="https://www.reddit.com/r/pihole/">Reddit</a></li>
|
||||||
- [Reddit](https://www.reddit.com/r/pihole/)
|
<li><a href="https://gitter.im/pi-hole/pi-hole">Gitter</a> (Real-time chat)</li>
|
||||||
- [Twitter](https://twitter.com/The_Pi_hole)
|
<li><a href="https://twitter.com/The_Pi_Hole">Twitter</a></li>
|
||||||
|
<li><a href="https://www.youtube.com/channel/UCT5kq9w0wSjogzJb81C9U0w">YouTube</a></li>
|
||||||
|
<li><a href="https://www.facebook.com/ThePiHole/">Facebook</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
## Breakdown of Features
|
## Breakdown of Features
|
||||||
|
### The Command Line Interface
|
||||||
|
The `pihole` 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`.
|
||||||
|
|
||||||
### [Faster-than-light Engine](https://github.com/pi-hole/ftl)
|
<a href="https://pi-hole.github.io/graphics/Screenshots/blacklist-cli.gif"><img src="https://pi-hole.github.io/graphics/Screenshots/blacklist-cli.gif" alt="Pi-hole Blacklist Demo"/></a>
|
||||||
|
|
||||||
[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 using:
|
|
||||||
- your browser: http://pi.hole/api/docs
|
|
||||||
- `curl`: `curl --connect-timeout 2 -ks "https://pi.hole/api/stats/summary" -H "Accept: application/json"`;
|
|
||||||
- the command line - examples: `pihole api config/webserver/port` or `pihole api stats/summary`.
|
|
||||||
|
|
||||||
### 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 for the Web Interface. It's fast, user-friendly, and auditable by anyone with an understanding of `bash`.
|
|
||||||
|
|
||||||
Some notable features include:
|
Some notable features include:
|
||||||
|
* [Whitelisting, Blacklisting and Wildcards](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#whitelisting-blacklisting-and-wildcards)
|
||||||
|
* [Debugging utility](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#debugger)
|
||||||
|
* [Viewing the live log file](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#tail)
|
||||||
|
* [Real-time Statistics via `ssh`](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#chronometer) or [your TFT LCD screen](http://www.amazon.com/exec/obidos/ASIN/B00ID39LM4/pihole09-20)
|
||||||
|
* [Updating Ad Lists](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#gravity)
|
||||||
|
* [Querying Ad Lists for blocked domains](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#query)
|
||||||
|
* [Enabling and Disabling Pi-hole](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#enable--disable)
|
||||||
|
* ... and *many* more!
|
||||||
|
|
||||||
- [Allowlisting, Denylisting (fka Whitelisting, Blacklisting), and Regex](https://docs.pi-hole.net/core/pihole-command/#allowlisting-denylisting-and-regex)
|
You can read our [Core Feature Breakdown](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown), as well as read up on [example usage](https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738) for more information.
|
||||||
- [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)
|
|
||||||
- [Querying Ad Lists for blocked domains](https://docs.pi-hole.net/core/pihole-command/#query)
|
|
||||||
- [Enabling and Disabling Pi-hole](https://docs.pi-hole.net/core/pihole-command/#enable-disable)
|
|
||||||
- ... and _many_ more!
|
|
||||||
|
|
||||||
You can read our [Core Feature Breakdown](https://docs.pi-hole.net/core/pihole-command/#pi-hole-core) for more information.
|
|
||||||
|
|
||||||
### The Web Interface Dashboard
|
### The Web Interface Dashboard
|
||||||
|
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!
|
||||||
|
|
||||||
This [optional dashboard](https://github.com/pi-hole/web) 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!
|
<img src="https://pi-hole.github.io/graphics/Screenshots/pihole-dashboard.png" alt="Pi-hole Dashboard"/></a>
|
||||||
|
|
||||||
Some notable features include:
|
Some notable features include:
|
||||||
|
* Mobile friendly interface
|
||||||
- Mobile-friendly interface
|
* Password protection
|
||||||
- Password protection
|
* Detailed graphs and doughnut charts
|
||||||
- Detailed graphs and doughnut charts
|
* Top lists of domains and clients
|
||||||
- Top lists of domains and clients
|
* A filterable and sortable query log
|
||||||
- A filterable and sortable query log
|
* Long Term Statistics to view data over user-defined time ranges
|
||||||
- Long Term Statistics to view data over user-defined time ranges
|
* The ability to easily manage and configure Pi-hole features
|
||||||
- The ability to easily manage and configure Pi-hole features
|
* ... and all the main features of the Command Line Interface!
|
||||||
- ... and all the main features of the Command Line Interface!
|
|
||||||
|
|
||||||
There are several ways to [access the dashboard](https://discourse.pi-hole.net/t/how-do-i-access-pi-holes-dashboard-admin-interface/3168):
|
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)
|
1. `http://<IP_ADDPRESS_OF_YOUR_PI_HOLE>/admin/`
|
||||||
2. `http://<IP_ADDRESS_OF_YOUR_PI_HOLE>/admin/`
|
2. `http://pi.hole/admin/` (when using Pi-hole as your DNS server)
|
||||||
|
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).
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
## The Origin Of Pi-hole
|
||||||
|
Pi-hole being an **advertising-aware DNS/Web server**, makes use of the following technologies:
|
||||||
|
|
||||||
|
* [`dnsmasq`](http://www.thekelleys.org.uk/dnsmasq/doc.html) - a lightweight DNS and DHCP server
|
||||||
|
* [`curl`](https://curl.haxx.se) - A command line tool for transferring data with URL syntax
|
||||||
|
* [`lighttpd`](https://www.lighttpd.net) - web server designed and optimized for high performance
|
||||||
|
* [`php`](https://secure.php.net) - a popular general-purpose web scripting language
|
||||||
|
* [AdminLTE Dashboard](https://github.com/almasaeed2010/AdminLTE) - premium admin control panel based on Bootstrap 3.x
|
||||||
|
|
||||||
|
While quite outdated at this point, [this original blog post about Pi-hole](https://jacobsalmela.com/2015/06/16/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0/) goes into **great detail** about how Pi-hole was originally set up and how it works. Syntactically, it's no longer accurate, but the same basic principles and logic still apply to Pi-hole's current state.
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
## Coverage
|
||||||
|
- [Lifehacker: Turn A Raspberry Pi Into An Ad Blocker With A Single Command](https://www.lifehacker.com.au/2015/02/turn-a-raspberry-pi-into-an-ad-blocker-with-a-single-command/) (Feburary, 2015)
|
||||||
|
- [MakeUseOf: Adblock Everywhere: The Raspberry Pi-Hole Way](http://www.makeuseof.com/tag/adblock-everywhere-raspberry-pi-hole-way/) (March, 2015)
|
||||||
|
- [Catchpoint: Ad-Blocking on Apple iOS9: Valuing the End User Experience](http://blog.catchpoint.com/2015/09/14/ad-blocking-apple/) (September, 2015)
|
||||||
|
- [Security Now Netcast: Pi-hole](https://www.youtube.com/watch?v=p7-osq_y8i8&t=100m26s) (October, 2015)
|
||||||
|
- [TekThing: Raspberry Pi-Hole Makes Ads Disappear!](https://youtu.be/8Co59HU2gY0?t=2m) (December, 2015)
|
||||||
|
- [Foolish Tech Show](https://youtu.be/bYyena0I9yc?t=2m4s) (December, 2015)
|
||||||
|
- [Block Ads on All Home Devices for $53.18](https://medium.com/@robleathern/block-ads-on-all-home-devices-for-53-18-a5f1ec139693#.gj1xpgr5d) (December, 2015)
|
||||||
|
- [Pi-Hole for Ubuntu 14.04](http://www.boyter.org/2015/12/pi-hole-ubuntu-14-04/) (December, 2015)
|
||||||
|
- [MacObserver Podcast 585](https://www.macobserver.com/tmo/podcast/macgeekgab-585) (December, 2015)
|
||||||
|
- [The Defrag Show: Endoscope USB Camera, The Final [HoloLens] Vote, Adblock Pi and more](https://channel9.msdn.com/Shows/The-Defrag-Show/Defrag-Endoscope-USB-Camera-The-Final-HoloLens-Vote-Adblock-Pi-and-more?WT.mc_id=dlvr_twitter_ch9#time=20m39s) (January, 2016)
|
||||||
|
- [Adafruit: Pi-hole is a black hole for internet ads](https://blog.adafruit.com/2016/03/04/pi-hole-is-a-black-hole-for-internet-ads-piday-raspberrypi-raspberry_pi/) (March, 2016)
|
||||||
|
- [Digital Trends: 5 Fun, Easy Projects You Can Try With a $35 Raspberry Pi](https://youtu.be/QwrKlyC2kdM?t=1m42s) (March, 2016)
|
||||||
|
- [Adafruit: Raspberry Pi Quick Look at Pi Hole ad blocking server with Tony D](https://www.youtube.com/watch?v=eg4u2j1HYlI) (June, 2016)
|
||||||
|
- [Devacron: OrangePi Zero as an Ad-Block server with Pi-Hole](http://www.devacron.com/orangepi-zero-as-an-ad-block-server-with-pi-hole/) (December, 2016)
|
||||||
|
- [Linux Pro: The Hole Truth](http://www.linuxpromagazine.com/Issues/2017/200/The-sysadmin-s-daily-grind-Pi-hole) (July, 2017)
|
||||||
|
- [Adafruit: installing Pi-hole on a Pi Zero W](https://learn.adafruit.com/pi-hole-ad-blocker-with-pi-zero-w/install-pi-hole) (August, 2017)
|
||||||
|
- [CryptoAUSTRALIA: How We Tried 5 Privacy Focused Raspberry Pi Projects](https://blog.cryptoaustralia.org.au/2017/10/05/5-privacy-focused-raspberry-pi-projects/) (October, 2017)
|
||||||
|
- [CryptoAUSTRALIA: Pi-hole Workshop](https://blog.cryptoaustralia.org.au/2017/11/02/pi-hole-network-wide-ad-blocker/) (November, 2017)
|
||||||
|
- [Know How 355: Killing ads with a Raspberry Pi-Hole!](https://www.twit.tv/shows/know-how/episodes/355) (November, 2017)
|
||||||
|
- [Hobohouse: Block Advertising on your Network with Pi-hole and Raspberry Pi](https://hobo.house/2018/02/27/block-advertising-with-pi-hole-and-raspberry-pi/) (March, 2018)
|
||||||
|
- [Scott Helme: Securing DNS across all of my devices with Pi-Hole + DNS-over-HTTPS + 1.1.1.1](https://scotthelme.co.uk/securing-dns-across-all-of-my-devices-with-pihole-dns-over-https-1-1-1-1/) (April, 2018)
|
||||||
|
- [Scott Helme: Catching and dealing with naughty devices on my home network](https://scotthelme.co.uk/catching-naughty-devices-on-my-home-network/) (April, 2018)
|
||||||
|
- [Bloomberg Business Week: Brotherhood of the Ad blockers](https://www.bloomberg.com/news/features/2018-05-10/inside-the-brotherhood-of-pi-hole-ad-blockers) (May, 2018)
|
||||||
|
- [Software Engineering Daily: Interview with the creator of Pi-hole](https://softwareengineeringdaily.com/2018/05/29/pi-hole-ad-blocker-hardware-with-jacob-salmela/) (May, 2018)
|
||||||
|
- [Raspberry Pi: Block ads at home using Pi-hole and a Raspberry Pi](https://www.raspberrypi.org/blog/pi-hole-raspberry-pi/) (July, 2018)
|
||||||
|
- [Troy Hunt: Mmm... Pi-hole...](https://www.troyhunt.com/mmm-pi-hole/) (September, 2018)
|
||||||
|
- [PEBKAK Podcast: Interview With Jacob Salmela](https://www.jerseystudios.net/2018/10/11/150-pi-hole/) (October, 2018)
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
## Pi-hole Projects
|
||||||
|
- [The Big Blocklist Collection](https://wally3k.github.io)
|
||||||
|
- [Pie in the Sky-Hole](https://dlaa.me/blog/post/skyhole)
|
||||||
|
- [Copernicus: Windows Tray Application](https://github.com/goldbattle/copernicus)
|
||||||
|
- [Magic Mirror with DNS Filtering](https://zonksec.com/blog/magic-mirror-dns-filtering/#dnssoftware)
|
||||||
|
- [Windows DNS Swapper](https://github.com/roots84/DNS-Swapper)
|
||||||
|
|||||||
43
advanced/01-pihole.conf
Normal file
43
advanced/01-pihole.conf
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Dnsmasq config for Pi-hole's FTLDNS
|
||||||
|
#
|
||||||
|
# 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 #
|
||||||
|
# #
|
||||||
|
# IF YOU WISH TO CHANGE THE UPSTREAM SERVERS, CHANGE THEM IN: #
|
||||||
|
# /etc/pihole/setupVars.conf #
|
||||||
|
# #
|
||||||
|
# ANY OTHER CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE #
|
||||||
|
# WITHIN /etc/dnsmasq.d/yourname.conf #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
addn-hosts=/etc/pihole/local.list
|
||||||
|
|
||||||
|
domain-needed
|
||||||
|
|
||||||
|
localise-queries
|
||||||
|
|
||||||
|
bogus-priv
|
||||||
|
|
||||||
|
no-resolv
|
||||||
|
|
||||||
|
server=@DNS1@
|
||||||
|
server=@DNS2@
|
||||||
|
|
||||||
|
interface=@INT@
|
||||||
|
|
||||||
|
cache-size=10000
|
||||||
|
|
||||||
|
log-queries
|
||||||
|
log-facility=/var/log/pihole.log
|
||||||
|
|
||||||
|
local-ttl=2
|
||||||
|
|
||||||
|
log-async
|
||||||
BIN
advanced/GIFs/25Bytes.gif
Normal file
BIN
advanced/GIFs/25Bytes.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 B |
BIN
advanced/GIFs/26Bytes.gif
Normal file
BIN
advanced/GIFs/26Bytes.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 B |
BIN
advanced/GIFs/37Bytes.gif
Normal file
BIN
advanced/GIFs/37Bytes.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 B |
BIN
advanced/GIFs/43Bytes.gif
Normal file
BIN
advanced/GIFs/43Bytes.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 B |
@@ -1,12 +1,10 @@
|
|||||||
#!/usr/bin/env sh
|
# Determine if terminal is capable of showing colours
|
||||||
# shellcheck disable=SC2034 # Disable warning about unused variables
|
if [[ -t 1 ]] && [[ $(tput colors) -ge 8 ]]; then
|
||||||
|
|
||||||
# Determine if terminal is capable of showing colors
|
|
||||||
# When COL_TABLE is sourced via gravity invoked by FTL, FORCE_COLOR is set to true
|
|
||||||
if { [ -t 1 ] && [ "$(tput colors)" -ge 8 ]; } || [ "${FORCE_COLOR}" ]; then
|
|
||||||
# Bold and underline may not show up on all clients
|
# Bold and underline may not show up on all clients
|
||||||
# If something MUST be emphasized, use both
|
# If something MUST be emphasised, use both
|
||||||
COL_BOLD='[1m'
|
COL_BOLD='[1m'
|
||||||
|
COL_ULINE='[4m'
|
||||||
|
|
||||||
COL_NC='[0m'
|
COL_NC='[0m'
|
||||||
COL_GRAY='[90m'
|
COL_GRAY='[90m'
|
||||||
COL_RED='[91m'
|
COL_RED='[91m'
|
||||||
@@ -18,6 +16,8 @@ if { [ -t 1 ] && [ "$(tput colors)" -ge 8 ]; } || [ "${FORCE_COLOR}" ]; then
|
|||||||
else
|
else
|
||||||
# Provide empty variables for `set -u`
|
# Provide empty variables for `set -u`
|
||||||
COL_BOLD=""
|
COL_BOLD=""
|
||||||
|
COL_ULINE=""
|
||||||
|
|
||||||
COL_NC=""
|
COL_NC=""
|
||||||
COL_GRAY=""
|
COL_GRAY=""
|
||||||
COL_RED=""
|
COL_RED=""
|
||||||
@@ -28,8 +28,22 @@ else
|
|||||||
COL_CYAN=""
|
COL_CYAN=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Deprecated variables
|
||||||
|
COL_WHITE="${COL_BOLD}"
|
||||||
|
COL_BLACK="${COL_NC}"
|
||||||
|
COL_LIGHT_BLUE="${COL_BLUE}"
|
||||||
|
COL_LIGHT_GREEN="${COL_GREEN}"
|
||||||
|
COL_LIGHT_CYAN="${COL_CYAN}"
|
||||||
|
COL_LIGHT_RED="${COL_RED}"
|
||||||
|
COL_URG_RED="${COL_RED}${COL_BOLD}${COL_ULINE}"
|
||||||
|
COL_LIGHT_PURPLE="${COL_PURPLE}"
|
||||||
|
COL_BROWN="${COL_YELLOW}"
|
||||||
|
COL_LIGHT_GRAY="${COL_GRAY}"
|
||||||
|
COL_DARK_GRAY="${COL_GRAY}"
|
||||||
|
|
||||||
TICK="[${COL_GREEN}✓${COL_NC}]"
|
TICK="[${COL_GREEN}✓${COL_NC}]"
|
||||||
CROSS="[${COL_RED}✗${COL_NC}]"
|
CROSS="[${COL_RED}✗${COL_NC}]"
|
||||||
INFO="[i]"
|
INFO="[i]"
|
||||||
QST="[?]"
|
QST="[?]"
|
||||||
|
DONE="${COL_GREEN} done!${COL_NC}"
|
||||||
OVER="\\r[K"
|
OVER="\\r[K"
|
||||||
|
|||||||
@@ -1,376 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# 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 api 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.
|
|
||||||
|
|
||||||
|
|
||||||
# The basic usage steps are
|
|
||||||
# 1) Test Availability of the API
|
|
||||||
# 2) Try to authenticate (read password if needed)
|
|
||||||
# 3) Get the data from the API endpoint
|
|
||||||
# 4) Delete the session
|
|
||||||
|
|
||||||
|
|
||||||
TestAPIAvailability() {
|
|
||||||
|
|
||||||
local chaos_api_list authResponse authStatus authData apiAvailable DNSport
|
|
||||||
|
|
||||||
# as we are running locally, we can get the port value from FTL directly
|
|
||||||
PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
|
||||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
|
||||||
# shellcheck source=./advanced/Scripts/utils.sh
|
|
||||||
. "${utilsfile}"
|
|
||||||
|
|
||||||
DNSport=$(getFTLConfigValue dns.port)
|
|
||||||
|
|
||||||
# Query the API URLs from FTL using CHAOS TXT local.api.ftl
|
|
||||||
# The result is a space-separated enumeration of full URLs
|
|
||||||
# e.g., "http://localhost:80/api/" "https://localhost:443/api/"
|
|
||||||
chaos_api_list="$(dig +short -p "${DNSport}" chaos txt local.api.ftl @127.0.0.1)"
|
|
||||||
|
|
||||||
# If the query was not successful, the variable is empty
|
|
||||||
if [ -z "${chaos_api_list}" ]; then
|
|
||||||
echo "API not available. Please check connectivity"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If an error occurred, the variable starts with ;;
|
|
||||||
if [ "${chaos_api_list#;;}" != "${chaos_api_list}" ]; then
|
|
||||||
echo "Communication error. Is FTL running?"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Iterate over space-separated list of URLs
|
|
||||||
while [ -n "${chaos_api_list}" ]; do
|
|
||||||
# Get the first URL
|
|
||||||
API_URL="${chaos_api_list%% *}"
|
|
||||||
# Strip leading and trailing quotes
|
|
||||||
API_URL="${API_URL%\"}"
|
|
||||||
API_URL="${API_URL#\"}"
|
|
||||||
|
|
||||||
# Test if the API is available at this URL, include delimiter for ease in splitting payload
|
|
||||||
authResponse=$(curl --connect-timeout 2 -skS -w ">>%{http_code}" "${API_URL}auth")
|
|
||||||
|
|
||||||
# authStatus is the response http_code, eg. 200, 401.
|
|
||||||
# Shell parameter expansion, remove everything up to and including the >> delim
|
|
||||||
authStatus=${authResponse#*>>}
|
|
||||||
# data is everything from response
|
|
||||||
# Shell parameter expansion, remove the >> delim and everything after
|
|
||||||
authData=${authResponse%>>*}
|
|
||||||
|
|
||||||
# Test if http status code was 200 (OK) or 401 (authentication required)
|
|
||||||
if [ "${authStatus}" = 200 ]; then
|
|
||||||
# API is available without authentication
|
|
||||||
apiAvailable=true
|
|
||||||
needAuth=false
|
|
||||||
break
|
|
||||||
|
|
||||||
elif [ "${authStatus}" = 401 ]; then
|
|
||||||
# API is available with authentication
|
|
||||||
apiAvailable=true
|
|
||||||
needAuth=true
|
|
||||||
# Check if 2FA is required
|
|
||||||
needTOTP=$(echo "${authData}"| jq --raw-output .session.totp 2>/dev/null)
|
|
||||||
break
|
|
||||||
|
|
||||||
else
|
|
||||||
# API is not available at this port/protocol combination
|
|
||||||
apiAvailable=false
|
|
||||||
# Remove the first URL from the list
|
|
||||||
local last_api_list
|
|
||||||
last_api_list="${chaos_api_list}"
|
|
||||||
chaos_api_list="${chaos_api_list#* }"
|
|
||||||
|
|
||||||
# If the list did not change, we are at the last element
|
|
||||||
if [ "${last_api_list}" = "${chaos_api_list}" ]; then
|
|
||||||
# Remove the last element
|
|
||||||
chaos_api_list=""
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# if apiAvailable is false, no working API was found
|
|
||||||
if [ "${apiAvailable}" = false ]; then
|
|
||||||
echo "API not available. Please check FTL.log"
|
|
||||||
echo "Exiting."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
LoginAPI() {
|
|
||||||
# If the API URL is not set, test the availability
|
|
||||||
if [ -z "${API_URL}" ]; then
|
|
||||||
TestAPIAvailability
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Exit early if authentication is not needed
|
|
||||||
if [ "${needAuth}" = false ]; then
|
|
||||||
if [ "${1}" = "verbose" ]; then
|
|
||||||
echo "API Authentication: Not needed"
|
|
||||||
fi
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Try to read the CLI password (if enabled and readable by the current user)
|
|
||||||
if [ -r /etc/pihole/cli_pw ]; then
|
|
||||||
password=$(cat /etc/pihole/cli_pw)
|
|
||||||
|
|
||||||
if [ "${1}" = "verbose" ]; then
|
|
||||||
echo "API Authentication: Trying to use CLI password"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If we can read the CLI password, we can skip 2FA even when it's required otherwise
|
|
||||||
needTOTP=false
|
|
||||||
elif [ "${1}" = "verbose" ]; then
|
|
||||||
echo "API Authentication: CLI password not available"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${password}" ]; then
|
|
||||||
# no password read from CLI file
|
|
||||||
echo "Please enter your password:"
|
|
||||||
# secretly read the password
|
|
||||||
secretRead; printf '\n'
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${needTOTP}" = true ]; then
|
|
||||||
# 2FA required
|
|
||||||
echo "Please enter the correct second factor."
|
|
||||||
echo "(Can be any number if you used the app password)"
|
|
||||||
read -r totp
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Try to authenticate using the supplied password (CLI file or user input) and TOTP
|
|
||||||
Authentication "${1}"
|
|
||||||
|
|
||||||
# Try to login again until the session is valid
|
|
||||||
while [ ! "${validSession}" = true ] ; do
|
|
||||||
|
|
||||||
# Print the error message if there is one
|
|
||||||
if [ ! "${sessionError}" = "null" ] && [ "${1}" = "verbose" ]; then
|
|
||||||
echo "Error: ${sessionError}"
|
|
||||||
fi
|
|
||||||
# Print the session message if there is one
|
|
||||||
if [ ! "${sessionMessage}" = "null" ] && [ "${1}" = "verbose" ]; then
|
|
||||||
echo "Error: ${sessionMessage}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${1}" = "verbose" ]; then
|
|
||||||
# If we are not in verbose mode, no need to print the error message again
|
|
||||||
echo "Please enter your Pi-hole password"
|
|
||||||
else
|
|
||||||
|
|
||||||
echo "Authentication failed. Please enter your Pi-hole password"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# secretly read the password
|
|
||||||
secretRead; printf '\n'
|
|
||||||
|
|
||||||
if [ "${needTOTP}" = true ]; then
|
|
||||||
echo "Please enter the correct second factor:"
|
|
||||||
echo "(Can be any number if you used the app password)"
|
|
||||||
read -r totp
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Try to authenticate again
|
|
||||||
Authentication "${1}"
|
|
||||||
done
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Authentication() {
|
|
||||||
sessionResponse="$(curl --connect-timeout 2 -skS -X POST "${API_URL}auth" --user-agent "Pi-hole cli" --data "{\"password\":\"${password}\", \"totp\":${totp:-null}}" )"
|
|
||||||
|
|
||||||
if [ -z "${sessionResponse}" ]; then
|
|
||||||
echo "No response from FTL server. Please check connectivity"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# obtain validity, session ID, sessionMessage and error message from
|
|
||||||
# session response, apply default values if none returned
|
|
||||||
result=$(echo "${sessionResponse}" | jq -r '
|
|
||||||
(.session.valid // false),
|
|
||||||
(.session.sid // null),
|
|
||||||
(.session.message // null),
|
|
||||||
(.error.message // null)
|
|
||||||
' 2>/dev/null)
|
|
||||||
|
|
||||||
validSession=$(echo "${result}" | sed -n '1p')
|
|
||||||
SID=$(echo "${result}" | sed -n '2p')
|
|
||||||
sessionMessage=$(echo "${result}" | sed -n '3p')
|
|
||||||
sessionError=$(echo "${result}" | sed -n '4p')
|
|
||||||
|
|
||||||
if [ "${1}" = "verbose" ]; then
|
|
||||||
if [ "${validSession}" = true ]; then
|
|
||||||
echo "API Authentication: ${COL_GREEN}Success${COL_NC}"
|
|
||||||
else
|
|
||||||
echo "API Authentication: ${COL_RED}Failed${COL_NC}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
LogoutAPI() {
|
|
||||||
# if a valid Session exists (no password required or successful Authentication) and
|
|
||||||
# SID is not null (successful Authentication only), delete the session
|
|
||||||
if [ "${validSession}" = true ] && [ ! "${SID}" = null ]; then
|
|
||||||
# Try to delete the session. Omit the output, but get the http status code
|
|
||||||
deleteResponse=$(curl -skS -o /dev/null -w "%{http_code}" -X DELETE "${API_URL}auth" -H "Accept: application/json" -H "sid: ${SID}")
|
|
||||||
|
|
||||||
case "${deleteResponse}" in
|
|
||||||
"401") echo "Logout attempt without a valid session. Unauthorized!";;
|
|
||||||
"204") if [ "${1}" = "verbose" ]; then echo "API Logout: ${COL_GREEN}Success${COL_NC} (session deleted)"; fi;;
|
|
||||||
esac;
|
|
||||||
elif [ "${1}" = "verbose" ]; then
|
|
||||||
echo "API Logout: ${COL_GREEN}Success${COL_NC} (no valid session)"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
GetFTLData() {
|
|
||||||
local data response status
|
|
||||||
# get the data from querying the API as well as the http status code
|
|
||||||
response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1" -H "Accept: application/json" -H "sid: ${SID}" )
|
|
||||||
|
|
||||||
if [ "${2}" = "raw" ]; then
|
|
||||||
# return the raw response
|
|
||||||
echo "${response}"
|
|
||||||
else
|
|
||||||
|
|
||||||
# status are the last 3 characters
|
|
||||||
# not using ${response#"${response%???}"}" here because it's extremely slow on big responses
|
|
||||||
status=$(printf "%s" "${response}" | tail -c 3)
|
|
||||||
# data is everything from response without the last 3 characters
|
|
||||||
data="${response%???}"
|
|
||||||
|
|
||||||
# return only the data
|
|
||||||
if [ "${status}" = 200 ]; then
|
|
||||||
# response OK
|
|
||||||
printf %s "${data}"
|
|
||||||
else
|
|
||||||
# connection lost
|
|
||||||
echo "${status}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
PostFTLData() {
|
|
||||||
local data response status
|
|
||||||
# send the data to the API
|
|
||||||
response=$(curl -skS -w "%{http_code}" -X POST "${API_URL}$1" --data-raw "$2" -H "Accept: application/json" -H "sid: ${SID}" )
|
|
||||||
# data is everything from response without the last 3 characters
|
|
||||||
if [ "${3}" = "status" ]; then
|
|
||||||
# Keep the status code appended if requested
|
|
||||||
printf %s "${response}"
|
|
||||||
else
|
|
||||||
# Strip the status code
|
|
||||||
printf %s "${response%???}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
secretRead() {
|
|
||||||
|
|
||||||
# POSIX compliant function to read user-input and
|
|
||||||
# mask every character entered by (*)
|
|
||||||
#
|
|
||||||
# This is challenging, because in POSIX, `read` does not support
|
|
||||||
# `-s` option (suppressing the input) or
|
|
||||||
# `-n` option (reading n chars)
|
|
||||||
|
|
||||||
|
|
||||||
# This workaround changes the terminal characteristics to not echo input and later resets this option
|
|
||||||
# credits https://stackoverflow.com/a/4316765
|
|
||||||
# showing asterisk instead of password
|
|
||||||
# https://stackoverflow.com/a/24600839
|
|
||||||
# https://unix.stackexchange.com/a/464963
|
|
||||||
|
|
||||||
|
|
||||||
# Save current terminal settings (needed for later restore after password prompt)
|
|
||||||
stty_orig=$(stty -g)
|
|
||||||
|
|
||||||
stty -echo # do not echo user input
|
|
||||||
stty -icanon min 1 time 0 # disable canonical mode https://man7.org/linux/man-pages/man3/termios.3.html
|
|
||||||
|
|
||||||
unset password
|
|
||||||
unset key
|
|
||||||
unset charcount
|
|
||||||
charcount=0
|
|
||||||
while key=$(dd ibs=1 count=1 2>/dev/null); do #read one byte of input
|
|
||||||
if [ "${key}" = "$(printf '\0' | tr -d '\0')" ] ; then
|
|
||||||
# Enter - accept password
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
if [ "${key}" = "$(printf '\177')" ] ; then
|
|
||||||
# Backspace
|
|
||||||
if [ $charcount -gt 0 ] ; then
|
|
||||||
charcount=$((charcount-1))
|
|
||||||
printf '\b \b'
|
|
||||||
password="${password%?}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# any other character
|
|
||||||
charcount=$((charcount+1))
|
|
||||||
printf '*'
|
|
||||||
password="$password$key"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# restore original terminal settings
|
|
||||||
stty "${stty_orig}"
|
|
||||||
}
|
|
||||||
|
|
||||||
apiFunc() {
|
|
||||||
local data response status status_col verbosity
|
|
||||||
|
|
||||||
# Define if the output will be silent (default) or verbose
|
|
||||||
verbosity="silent"
|
|
||||||
if [ "$1" = "verbose" ]; then
|
|
||||||
verbosity="verbose"
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Authenticate with the API
|
|
||||||
LoginAPI "${verbosity}"
|
|
||||||
|
|
||||||
if [ "${verbosity}" = "verbose" ]; then
|
|
||||||
echo ""
|
|
||||||
echo "Requesting: ${COL_PURPLE}GET ${COL_CYAN}${API_URL}${COL_YELLOW}$1${COL_NC}"
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get the data from the API
|
|
||||||
response=$(GetFTLData "$1" raw)
|
|
||||||
|
|
||||||
# status are the last 3 characters
|
|
||||||
# not using ${response#"${response%???}"}" here because it's extremely slow on big responses
|
|
||||||
status=$(printf "%s" "${response}" | tail -c 3)
|
|
||||||
# data is everything from response without the last 3 characters
|
|
||||||
data="${response%???}"
|
|
||||||
|
|
||||||
# Output the status (200 -> green, else red)
|
|
||||||
if [ "${status}" = 200 ]; then
|
|
||||||
status_col="${COL_GREEN}"
|
|
||||||
else
|
|
||||||
status_col="${COL_RED}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Only print the status in verbose mode or if the status is not 200
|
|
||||||
if [ "${verbosity}" = "verbose" ] || [ "${status}" != 200 ]; then
|
|
||||||
echo "Status: ${status_col}${status}${COL_NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Output the data. Format it with jq if available and data is actually JSON.
|
|
||||||
# Otherwise just print it
|
|
||||||
if [ "${verbosity}" = "verbose" ]; then
|
|
||||||
echo "Data:"
|
|
||||||
fi
|
|
||||||
# Attempt to print the data with jq, if it is not valid JSON, or not installed
|
|
||||||
# then print the plain text.
|
|
||||||
echo "${data}" | jq . 2>/dev/null || echo "${data}"
|
|
||||||
|
|
||||||
# Delete the session
|
|
||||||
LogoutAPI "${verbosity}"
|
|
||||||
}
|
|
||||||
571
advanced/Scripts/chronometer.sh
Executable file
571
advanced/Scripts/chronometer.sh
Executable file
@@ -0,0 +1,571 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC1090,SC1091
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Calculates stats and displays to an LCD
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
LC_ALL=C
|
||||||
|
LC_NUMERIC=C
|
||||||
|
|
||||||
|
# Retrieve stats from FTL engine
|
||||||
|
pihole-FTL() {
|
||||||
|
ftl_port=$(cat /var/run/pihole-FTL.port 2> /dev/null)
|
||||||
|
if [[ -n "$ftl_port" ]]; then
|
||||||
|
# Open connection to FTL
|
||||||
|
exec 3<>"/dev/tcp/127.0.0.1/$ftl_port"
|
||||||
|
|
||||||
|
# Test if connection is open
|
||||||
|
if { "true" >&3; } 2> /dev/null; then
|
||||||
|
# Send command to FTL
|
||||||
|
echo -e ">$1" >&3
|
||||||
|
|
||||||
|
# Read input
|
||||||
|
read -r -t 1 LINE <&3
|
||||||
|
until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do
|
||||||
|
echo "$LINE" >&1
|
||||||
|
read -r -t 1 LINE <&3
|
||||||
|
done
|
||||||
|
|
||||||
|
# Close connection
|
||||||
|
exec 3>&-
|
||||||
|
exec 3<&-
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "0"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print spaces to align right-side additional text
|
||||||
|
printFunc() {
|
||||||
|
local text_last
|
||||||
|
|
||||||
|
title="$1"
|
||||||
|
title_len="${#title}"
|
||||||
|
|
||||||
|
text_main="$2"
|
||||||
|
text_main_nocol="$text_main"
|
||||||
|
if [[ "${text_main:0:1}" == "" ]]; then
|
||||||
|
text_main_nocol=$(sed 's/\[[0-9;]\{1,5\}m//g' <<< "$text_main")
|
||||||
|
fi
|
||||||
|
text_main_len="${#text_main_nocol}"
|
||||||
|
|
||||||
|
text_addn="$3"
|
||||||
|
if [[ "$text_addn" == "last" ]]; then
|
||||||
|
text_addn=""
|
||||||
|
text_last="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If there is additional text, define max length of text_main
|
||||||
|
if [[ -n "$text_addn" ]]; then
|
||||||
|
case "$scr_cols" in
|
||||||
|
[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-4]) text_main_max_len="9";;
|
||||||
|
4[5-9]) text_main_max_len="14";;
|
||||||
|
*) text_main_max_len="19";;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -z "$text_addn" ]] && text_main_max_len="$(( scr_cols - title_len ))"
|
||||||
|
|
||||||
|
# Remove excess characters from main text
|
||||||
|
if [[ "$text_main_len" -gt "$text_main_max_len" ]]; then
|
||||||
|
# Trim text without colours
|
||||||
|
text_main_trim="${text_main_nocol:0:$text_main_max_len}"
|
||||||
|
# Replace with trimmed text
|
||||||
|
text_main="${text_main/$text_main_nocol/$text_main_trim}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine amount of spaces for each line
|
||||||
|
if [[ -n "$text_last" ]]; then
|
||||||
|
# Move cursor to end of screen
|
||||||
|
spc_num=$(( scr_cols - ( title_len + text_main_len ) ))
|
||||||
|
else
|
||||||
|
spc_num=$(( text_main_max_len - text_main_len ))
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ "$spc_num" -le 0 ]] && spc_num="0"
|
||||||
|
spc=$(printf "%${spc_num}s")
|
||||||
|
#spc="${spc// /.}" # Debug: Visualise spaces
|
||||||
|
|
||||||
|
printf "%s%s$spc" "$title" "$text_main"
|
||||||
|
|
||||||
|
if [[ -n "$text_addn" ]]; then
|
||||||
|
printf "%s(%s)%s\\n" "$COL_NC$COL_DARK_GRAY" "$text_addn" "$COL_NC"
|
||||||
|
else
|
||||||
|
# Do not print trailing newline on final line
|
||||||
|
[[ -z "$text_last" ]] && printf "%s\\n" "$COL_NC"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform on first Chrono run (not for JSON formatted string)
|
||||||
|
get_init_stats() {
|
||||||
|
calcFunc(){ awk "BEGIN {print $*}" 2> /dev/null; }
|
||||||
|
|
||||||
|
# Convert bytes to human-readable format
|
||||||
|
hrBytes() {
|
||||||
|
awk '{
|
||||||
|
num=$1;
|
||||||
|
if(num==0) {
|
||||||
|
print "0 B"
|
||||||
|
} else {
|
||||||
|
xxx=(num<0?-num:num)
|
||||||
|
sss=(num<0?-1:1)
|
||||||
|
split("B KB MB GB TB PB",type)
|
||||||
|
for(i=5;yyy < 1;i--) {
|
||||||
|
yyy=xxx / (2^(10*i))
|
||||||
|
}
|
||||||
|
printf "%.0f " type[i+2], yyy*sss
|
||||||
|
}
|
||||||
|
}' <<< "$1";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert seconds to human-readable format
|
||||||
|
hrSecs() {
|
||||||
|
day=$(( $1/60/60/24 )); hrs=$(( $1/3600%24 ))
|
||||||
|
mins=$(( ($1%3600)/60 )); secs=$(( $1%60 ))
|
||||||
|
[[ "$day" -ge "2" ]] && plu="s"
|
||||||
|
[[ "$day" -ge "1" ]] && days="$day day${plu}, " || days=""
|
||||||
|
printf "%s%02d:%02d:%02d\\n" "$days" "$hrs" "$mins" "$secs"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set Colour Codes
|
||||||
|
coltable="/opt/pihole/COL_TABLE"
|
||||||
|
if [[ -f "${coltable}" ]]; then
|
||||||
|
source ${coltable}
|
||||||
|
else
|
||||||
|
COL_NC="[0m"
|
||||||
|
COL_DARK_GRAY="[1;30m"
|
||||||
|
COL_LIGHT_GREEN="[1;32m"
|
||||||
|
COL_LIGHT_BLUE="[1;34m"
|
||||||
|
COL_LIGHT_RED="[1;31m"
|
||||||
|
COL_YELLOW="[1;33m"
|
||||||
|
COL_LIGHT_RED="[1;31m"
|
||||||
|
COL_URG_RED="[39;41m"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get RPi throttle state (RPi 3B only) & model number, or OS distro info
|
||||||
|
if command -v vcgencmd &> /dev/null; then
|
||||||
|
local sys_throttle_raw
|
||||||
|
local sys_rev_raw
|
||||||
|
|
||||||
|
sys_throttle_raw=$(vgt=$(sudo vcgencmd get_throttled); echo "${vgt##*x}")
|
||||||
|
|
||||||
|
# Active Throttle Notice: http://bit.ly/2gnunOo
|
||||||
|
if [[ "$sys_throttle_raw" != "0" ]]; then
|
||||||
|
case "$sys_throttle_raw" in
|
||||||
|
*0001) thr_type="${COL_YELLOW}Under Voltage";;
|
||||||
|
*0002) thr_type="${COL_LIGHT_BLUE}Arm Freq Cap";;
|
||||||
|
*0003) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC";;
|
||||||
|
*0004) thr_type="${COL_LIGHT_RED}Throttled";;
|
||||||
|
*0005) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
|
||||||
|
*0006) thr_type="${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
|
||||||
|
*0007) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
|
||||||
|
esac
|
||||||
|
[[ -n "$thr_type" ]] && sys_throttle="$thr_type${COL_DARK_GRAY}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sys_rev_raw=$(awk '/Revision/ {print $3}' < /proc/cpuinfo)
|
||||||
|
case "$sys_rev_raw" in
|
||||||
|
000[2-6]) sys_model=" 1, Model B";; # 256MB
|
||||||
|
000[7-9]) sys_model=" 1, Model A";; # 256MB
|
||||||
|
000d|000e|000f) sys_model=" 1, Model B";; # 512MB
|
||||||
|
0010|0013) sys_model=" 1, Model B+";; # 512MB
|
||||||
|
0012|0015) sys_model=" 1, Model A+";; # 256MB
|
||||||
|
a0104[0-1]|a21041|a22042) sys_model=" 2, Model B";; # 1GB
|
||||||
|
900021) sys_model=" 1, Model A+";; # 512MB
|
||||||
|
900032) sys_model=" 1, Model B+";; # 512MB
|
||||||
|
90009[2-3]|920093) sys_model=" Zero";; # 512MB
|
||||||
|
9000c1) sys_model=" Zero W";; # 512MB
|
||||||
|
a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB
|
||||||
|
a020d3) sys_model=" 3, Model B+";; # 1GB
|
||||||
|
*) sys_model="";;
|
||||||
|
esac
|
||||||
|
sys_type="Raspberry Pi$sys_model"
|
||||||
|
else
|
||||||
|
source "/etc/os-release"
|
||||||
|
CODENAME=$(sed 's/[()]//g' <<< "${VERSION/* /}")
|
||||||
|
sys_type="${NAME/ */} ${CODENAME^} $VERSION_ID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get core count
|
||||||
|
sys_cores=$(grep -c "^processor" /proc/cpuinfo)
|
||||||
|
|
||||||
|
# Test existence of clock speed file for ARM CPU
|
||||||
|
if [[ -f "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]]; then
|
||||||
|
scaling_freq_file="/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test existence of temperature file
|
||||||
|
if [[ -f "/sys/class/thermal/thermal_zone0/temp" ]]; then
|
||||||
|
temp_file="/sys/class/thermal/thermal_zone0/temp"
|
||||||
|
elif [[ -f "/sys/class/hwmon/hwmon0/temp1_input" ]]; then
|
||||||
|
temp_file="/sys/class/hwmon/hwmon0/temp1_input"
|
||||||
|
else
|
||||||
|
temp_file=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test existence of setupVars config
|
||||||
|
if [[ -f "/etc/pihole/setupVars.conf" ]]; then
|
||||||
|
setupVars="/etc/pihole/setupVars.conf"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_sys_stats() {
|
||||||
|
local ph_ver_raw
|
||||||
|
local cpu_raw
|
||||||
|
local ram_raw
|
||||||
|
local disk_raw
|
||||||
|
|
||||||
|
# Update every 12 refreshes (Def: every 60s)
|
||||||
|
count=$((count+1))
|
||||||
|
if [[ "$count" == "1" ]] || (( "$count" % 12 == 0 )); then
|
||||||
|
# Do not source setupVars if file does not exist
|
||||||
|
[[ -n "$setupVars" ]] && source "$setupVars"
|
||||||
|
|
||||||
|
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]}"
|
||||||
|
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"
|
||||||
|
|
||||||
|
# Get storage stats for partition mounted on /
|
||||||
|
read -r -a disk_raw <<< "$(df -B1 / 2> /dev/null | awk 'END{ print $3,$2,$5 }')"
|
||||||
|
disk_used="${disk_raw[0]}"
|
||||||
|
disk_total="${disk_raw[1]}"
|
||||||
|
disk_perc="${disk_raw[2]}"
|
||||||
|
|
||||||
|
net_gateway=$(ip route | grep default | cut -d ' ' -f 3 | head -n 1)
|
||||||
|
|
||||||
|
# Get DHCP stats, if feature is enabled
|
||||||
|
if [[ "$DHCP_ACTIVE" == "true" ]]; then
|
||||||
|
ph_dhcp_max=$(( ${DHCP_END##*.} - ${DHCP_START##*.} + 1 ))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get DNS server count
|
||||||
|
dns_count="0"
|
||||||
|
[[ -n "${PIHOLE_DNS_1}" ]] && dns_count=$((dns_count+1))
|
||||||
|
[[ -n "${PIHOLE_DNS_2}" ]] && dns_count=$((dns_count+1))
|
||||||
|
[[ -n "${PIHOLE_DNS_3}" ]] && dns_count=$((dns_count+1))
|
||||||
|
[[ -n "${PIHOLE_DNS_4}" ]] && dns_count=$((dns_count+1))
|
||||||
|
[[ -n "${PIHOLE_DNS_5}" ]] && dns_count=$((dns_count+1))
|
||||||
|
[[ -n "${PIHOLE_DNS_6}" ]] && dns_count=$((dns_count+1))
|
||||||
|
[[ -n "${PIHOLE_DNS_7}" ]] && dns_count=$((dns_count+1))
|
||||||
|
[[ -n "${PIHOLE_DNS_8}" ]] && dns_count=$((dns_count+1))
|
||||||
|
[[ -n "${PIHOLE_DNS_9}" ]] && dns_count="$dns_count+"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get screen size
|
||||||
|
read -r -a scr_size <<< "$(stty size 2>/dev/null || echo 24 80)"
|
||||||
|
scr_lines="${scr_size[0]}"
|
||||||
|
scr_cols="${scr_size[1]}"
|
||||||
|
|
||||||
|
# Determine Chronometer size behaviour
|
||||||
|
if [[ "$scr_cols" -ge 58 ]]; then
|
||||||
|
chrono_width="large"
|
||||||
|
elif [[ "$scr_cols" -gt 40 ]]; then
|
||||||
|
chrono_width="medium"
|
||||||
|
else
|
||||||
|
chrono_width="small"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine max length of divider string
|
||||||
|
scr_line_len=$(( scr_cols - 2 ))
|
||||||
|
[[ "$scr_line_len" -ge 58 ]] && scr_line_len="58"
|
||||||
|
scr_line_str=$(printf "%${scr_line_len}s")
|
||||||
|
scr_line_str="${scr_line_str// /—}"
|
||||||
|
|
||||||
|
sys_uptime=$(hrSecs "$(cut -d. -f1 /proc/uptime)")
|
||||||
|
sys_loadavg=$(cut -d " " -f1,2,3 /proc/loadavg)
|
||||||
|
|
||||||
|
# Get CPU usage, only counting processes over 1% as active
|
||||||
|
# shellcheck disable=SC2009
|
||||||
|
cpu_raw=$(ps -eo pcpu,rss --no-headers | grep -E -v " 0")
|
||||||
|
cpu_tasks=$(wc -l <<< "$cpu_raw")
|
||||||
|
cpu_taskact=$(sed -r "/(^ 0.)/d" <<< "$cpu_raw" | wc -l)
|
||||||
|
cpu_perc=$(awk '{sum+=$1} END {printf "%.0f\n", sum/'"$sys_cores"'}' <<< "$cpu_raw")
|
||||||
|
|
||||||
|
# Get CPU clock speed
|
||||||
|
if [[ -n "$scaling_freq_file" ]]; then
|
||||||
|
cpu_mhz=$(( $(< /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 ))
|
||||||
|
else
|
||||||
|
cpu_mhz=$(lscpu | awk -F ":" '/MHz/ {print $2;exit}')
|
||||||
|
cpu_mhz=$(printf "%.0f" "${cpu_mhz//[[:space:]]/}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine whether to display CPU clock speed as MHz or GHz
|
||||||
|
if [[ -n "$cpu_mhz" ]]; then
|
||||||
|
[[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(printf "%.1f" $(calcFunc "$cpu_mhz"/1000)) GHz"
|
||||||
|
[[ "${cpu_freq}" == *".0"* ]] && cpu_freq="${cpu_freq/.0/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine colour for temperature
|
||||||
|
if [[ -n "$temp_file" ]]; then
|
||||||
|
if [[ "$temp_unit" == "C" ]]; then
|
||||||
|
cpu_temp=$(printf "%.0fc\\n" "$(calcFunc "$(< $temp_file) / 1000")")
|
||||||
|
|
||||||
|
case "${cpu_temp::-1}" in
|
||||||
|
-*|[0-9]|[1-3][0-9]) cpu_col="$COL_LIGHT_BLUE";;
|
||||||
|
4[0-9]) cpu_col="";;
|
||||||
|
5[0-9]) cpu_col="$COL_YELLOW";;
|
||||||
|
6[0-9]) cpu_col="$COL_LIGHT_RED";;
|
||||||
|
*) 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"
|
||||||
|
|
||||||
|
elif [[ "$temp_unit" == "F" ]]; then
|
||||||
|
cpu_temp=$(printf "%.0ff\\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")")
|
||||||
|
|
||||||
|
case "${cpu_temp::-1}" in
|
||||||
|
-*|[0-9]|[0-9][0-9]) cpu_col="$COL_LIGHT_BLUE";;
|
||||||
|
1[0-1][0-9]) cpu_col="";;
|
||||||
|
1[2-3][0-9]) cpu_col="$COL_YELLOW";;
|
||||||
|
1[4-5][0-9]) cpu_col="$COL_LIGHT_RED";;
|
||||||
|
*) cpu_col="$COL_URG_RED";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
|
||||||
|
|
||||||
|
else
|
||||||
|
cpu_temp_str=$(printf " @ %.0fk\\n" "$(calcFunc "($(< $temp_file) / 1000) + 273.15")")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cpu_temp_str=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -r -a ram_raw <<< "$(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.0f %.0f %.0f", (total-free-buffers-cached)*100/total, (total-free-buffers-cached)*1024, total*1024}' /proc/meminfo)"
|
||||||
|
ram_perc="${ram_raw[0]}"
|
||||||
|
ram_used="${ram_raw[1]}"
|
||||||
|
ram_total="${ram_raw[2]}"
|
||||||
|
|
||||||
|
if [[ "$(pihole status web 2> /dev/null)" == "1" ]]; then
|
||||||
|
ph_status="${COL_LIGHT_GREEN}Active"
|
||||||
|
else
|
||||||
|
ph_status="${COL_LIGHT_RED}Offline"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$DHCP_ACTIVE" == "true" ]]; then
|
||||||
|
local ph_dhcp_range
|
||||||
|
|
||||||
|
ph_dhcp_range=$(seq -s "|" -f "${DHCP_START%.*}.%g" "${DHCP_START##*.}" "${DHCP_END##*.}")
|
||||||
|
|
||||||
|
# Count dynamic leases from available range, and not static leases
|
||||||
|
ph_dhcp_num=$(grep -cE "$ph_dhcp_range" "/etc/pihole/dhcp.leases")
|
||||||
|
ph_dhcp_percent=$(( ph_dhcp_num * 100 / ph_dhcp_max ))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_ftl_stats() {
|
||||||
|
local stats_raw
|
||||||
|
|
||||||
|
mapfile -t stats_raw < <(pihole-FTL "stats")
|
||||||
|
domains_being_blocked_raw="${stats_raw[0]#* }"
|
||||||
|
dns_queries_today_raw="${stats_raw[1]#* }"
|
||||||
|
ads_blocked_today_raw="${stats_raw[2]#* }"
|
||||||
|
ads_percentage_today_raw="${stats_raw[3]#* }"
|
||||||
|
queries_forwarded_raw="${stats_raw[5]#* }"
|
||||||
|
queries_cached_raw="${stats_raw[6]#* }"
|
||||||
|
|
||||||
|
# Only retrieve these stats when not called from jsonFunc
|
||||||
|
if [[ -z "$1" ]]; then
|
||||||
|
local top_ad_raw
|
||||||
|
local top_domain_raw
|
||||||
|
local top_client_raw
|
||||||
|
|
||||||
|
domains_being_blocked=$(printf "%.0f\\n" "${domains_being_blocked_raw}" 2> /dev/null)
|
||||||
|
dns_queries_today=$(printf "%.0f\\n" "${dns_queries_today_raw}")
|
||||||
|
ads_blocked_today=$(printf "%.0f\\n" "${ads_blocked_today_raw}")
|
||||||
|
ads_percentage_today=$(printf "%'.0f\\n" "${ads_percentage_today_raw}")
|
||||||
|
queries_cached_percentage=$(printf "%.0f\\n" "$(calcFunc "$queries_cached_raw * 100 / ( $queries_forwarded_raw + $queries_cached_raw )")")
|
||||||
|
recent_blocked=$(pihole-FTL recentBlocked)
|
||||||
|
read -r -a top_ad_raw <<< "$(pihole-FTL "top-ads (1)")"
|
||||||
|
read -r -a top_domain_raw <<< "$(pihole-FTL "top-domains (1)")"
|
||||||
|
read -r -a top_client_raw <<< "$(pihole-FTL "top-clients (1)")"
|
||||||
|
|
||||||
|
top_ad="${top_ad_raw[2]}"
|
||||||
|
top_domain="${top_domain_raw[2]}"
|
||||||
|
if [[ "${top_client_raw[3]}" ]]; then
|
||||||
|
top_client="${top_client_raw[3]}"
|
||||||
|
else
|
||||||
|
top_client="${top_client_raw[2]}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_strings() {
|
||||||
|
# Expand or contract strings depending on screen size
|
||||||
|
if [[ "$chrono_width" == "large" ]]; then
|
||||||
|
phc_str=" ${COL_DARK_GRAY}Core"
|
||||||
|
lte_str=" ${COL_DARK_GRAY}Web"
|
||||||
|
ftl_str=" ${COL_DARK_GRAY}FTL"
|
||||||
|
api_str="${COL_LIGHT_RED}API Offline"
|
||||||
|
|
||||||
|
host_info="$sys_type"
|
||||||
|
sys_info="$sys_throttle"
|
||||||
|
sys_info2="Active: $cpu_taskact of $cpu_tasks tasks"
|
||||||
|
used_str="Used: "
|
||||||
|
leased_str="Leased: "
|
||||||
|
domains_being_blocked=$(printf "%'.0f" "$domains_being_blocked")
|
||||||
|
ads_blocked_today=$(printf "%'.0f" "$ads_blocked_today")
|
||||||
|
dns_queries_today=$(printf "%'.0f" "$dns_queries_today")
|
||||||
|
ph_info="Blocking: $domains_being_blocked sites"
|
||||||
|
total_str="Total: "
|
||||||
|
else
|
||||||
|
phc_str=" ${COL_DARK_GRAY}Core"
|
||||||
|
lte_str=" ${COL_DARK_GRAY}Web"
|
||||||
|
ftl_str=" ${COL_DARK_GRAY}FTL"
|
||||||
|
api_str="${COL_LIGHT_RED}API Down"
|
||||||
|
ph_info="$domains_being_blocked blocked"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ "$sys_cores" -ne 1 ]] && sys_cores_txt="${sys_cores}x "
|
||||||
|
cpu_info="$sys_cores_txt$cpu_freq$cpu_temp_str"
|
||||||
|
ram_info="$used_str$(hrBytes "$ram_used") of $(hrBytes "$ram_total")"
|
||||||
|
disk_info="$used_str$(hrBytes "$disk_used") of $(hrBytes "$disk_total")"
|
||||||
|
|
||||||
|
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"
|
||||||
|
dns_info="$dns_count DNS servers"
|
||||||
|
|
||||||
|
[[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
chronoFunc() {
|
||||||
|
local extra_arg="$1"
|
||||||
|
local extra_value="$2"
|
||||||
|
|
||||||
|
get_init_stats
|
||||||
|
|
||||||
|
for (( ; ; )); do
|
||||||
|
get_sys_stats
|
||||||
|
get_ftl_stats
|
||||||
|
get_strings
|
||||||
|
|
||||||
|
# Strip excess development version numbers
|
||||||
|
if [[ "$ph_core_ver" != "-1" ]]; then
|
||||||
|
phc_ver_str="$phc_str: ${ph_core_ver%-*}${COL_NC}"
|
||||||
|
lte_ver_str="$lte_str: ${ph_lte_ver%-*}${COL_NC}"
|
||||||
|
ftl_ver_str="$ftl_str: ${ph_ftl_ver%-*}${COL_NC}"
|
||||||
|
else
|
||||||
|
phc_ver_str="$phc_str: $api_str${COL_NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get refresh number
|
||||||
|
if [[ "${extra_arg}" = "refresh" ]]; then
|
||||||
|
num="${extra_value}"
|
||||||
|
num_str="Refresh set for every $num seconds"
|
||||||
|
else
|
||||||
|
num_str=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
clear
|
||||||
|
|
||||||
|
# Remove exit message heading on third refresh
|
||||||
|
if [[ "$count" -le 2 ]] && [[ "${extra_arg}" != "exit" ]]; then
|
||||||
|
echo -e " ${COL_LIGHT_GREEN}Pi-hole Chronometer${COL_NC}
|
||||||
|
$num_str
|
||||||
|
${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}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printFunc " Hostname: " "$sys_name" "$host_info"
|
||||||
|
printFunc " Uptime: " "$sys_uptime" "$sys_info"
|
||||||
|
printFunc " Task Load: " "$sys_loadavg" "$sys_info2"
|
||||||
|
printFunc " CPU usage: " "$cpu_perc%" "$cpu_info"
|
||||||
|
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
|
||||||
|
|
||||||
|
printFunc " Pi-hole: " "$ph_status" "$ph_info"
|
||||||
|
printFunc " Ads Today: " "$ads_percentage_today%" "$ads_info"
|
||||||
|
printFunc "Local Qrys: " "$queries_cached_percentage%" "$dns_info"
|
||||||
|
|
||||||
|
printFunc " Blocked: " "$recent_blocked"
|
||||||
|
printFunc "Top Advert: " "$top_ad"
|
||||||
|
|
||||||
|
# Provide more stats on screens with more lines
|
||||||
|
if [[ "$scr_lines" -eq 17 ]]; then
|
||||||
|
if [[ "$DHCP_ACTIVE" == "true" ]]; then
|
||||||
|
printFunc "Top Domain: " "$top_domain" "last"
|
||||||
|
else
|
||||||
|
print_client="true"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_client="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$print_client" ]]; then
|
||||||
|
printFunc "Top Domain: " "$top_domain"
|
||||||
|
printFunc "Top Client: " "$top_client" "last"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Handle exit/refresh options
|
||||||
|
if [[ "${extra_arg}" == "exit" ]]; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
if [[ "${extra_arg}" == "refresh" ]]; then
|
||||||
|
sleep "$num"
|
||||||
|
else
|
||||||
|
sleep 5
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonFunc() {
|
||||||
|
get_ftl_stats "json"
|
||||||
|
echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
helpFunc() {
|
||||||
|
if [[ "$1" == "?" ]]; then
|
||||||
|
echo "Unknown option. Please view 'pihole -c --help' for more information"
|
||||||
|
else
|
||||||
|
echo "Usage: pihole -c [options]
|
||||||
|
Example: 'pihole -c -j'
|
||||||
|
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 witout refreshing
|
||||||
|
-h, --help Display this help text"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ $# = 0 ]]; then
|
||||||
|
chronoFunc
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
"-j" | "--json" ) jsonFunc;;
|
||||||
|
"-h" | "--help" ) helpFunc;;
|
||||||
|
"-r" | "--refresh" ) chronoFunc refresh "$2";;
|
||||||
|
"-e" | "--exit" ) chronoFunc exit;;
|
||||||
|
* ) helpFunc "?";;
|
||||||
|
esac
|
||||||
162
advanced/Scripts/database_migration/gravity-db.sh
Executable file → Normal file
162
advanced/Scripts/database_migration/gravity-db.sh
Executable file → Normal file
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
|
||||||
# Pi-hole: A black hole for Internet advertisements
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
# (c) 2019 Pi-hole, LLC (https://pi-hole.net)
|
# (c) 2019 Pi-hole, LLC (https://pi-hole.net)
|
||||||
@@ -10,150 +10,26 @@
|
|||||||
# This file is copyright under the latest version of the EUPL.
|
# This file is copyright under the latest version of the EUPL.
|
||||||
# Please see LICENSE file for your rights under this license.
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
readonly scriptPath="/etc/.pihole/advanced/Scripts/database_migration/gravity"
|
|
||||||
|
|
||||||
upgrade_gravityDB(){
|
upgrade_gravityDB(){
|
||||||
local database version
|
local database piholeDir auditFile version
|
||||||
database="${1}"
|
database="${1}"
|
||||||
|
piholeDir="${2}"
|
||||||
|
auditFile="${piholeDir}/auditlog.list"
|
||||||
|
|
||||||
# Exit early if the database does not exist (e.g. in CI tests)
|
# Get database version
|
||||||
if [[ ! -f "${database}" ]]; then
|
version="$(sqlite3 "${database}" "SELECT \"value\" FROM \"info\" WHERE \"property\" = 'version';")"
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get database version
|
if [[ "$version" == "1" ]]; then
|
||||||
version="$(pihole-FTL sqlite3 -ni "${database}" "SELECT \"value\" FROM \"info\" WHERE \"property\" = 'version';")"
|
# This migration script upgrades the gravity.db file by
|
||||||
|
# adding the domain_audit table
|
||||||
|
sqlite3 "${database}" < "/etc/.pihole/advanced/Scripts/database_migration/gravity/1_to_2.sql"
|
||||||
|
version=2
|
||||||
|
|
||||||
if [[ "$version" == "1" ]]; then
|
# Store audit domains in database table
|
||||||
# This migration script upgraded the gravity.db file by
|
if [ -e "${auditFile}" ]; then
|
||||||
# adding the domain_audit table. It is now a no-op
|
echo -e " ${INFO} Migrating content of ${auditFile} into new database"
|
||||||
echo -e " ${INFO} Upgrading gravity database from version 1 to 2"
|
# database_table_from_file is defined in gravity.sh
|
||||||
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/1_to_2.sql"
|
database_table_from_file "domain_audit" "${auditFile}"
|
||||||
version=2
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ "$version" == "2" ]]; then
|
|
||||||
# This migration script upgrades the gravity.db file by
|
|
||||||
# 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 -ni "${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 -ni "${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 -ni "${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 -ni "${database}" < "${scriptPath}/5_to_6.sql"
|
|
||||||
version=6
|
|
||||||
fi
|
|
||||||
if [[ "$version" == "6" ]]; then
|
|
||||||
# This migration script adds a special group with ID 0
|
|
||||||
# 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 -ni "${database}" < "${scriptPath}/6_to_7.sql"
|
|
||||||
version=7
|
|
||||||
fi
|
|
||||||
if [[ "$version" == "7" ]]; then
|
|
||||||
# This migration script recreated the group table
|
|
||||||
# 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 -ni "${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 -ni "${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 -ni "${database}" < "${scriptPath}/9_to_10.sql"
|
|
||||||
version=10
|
|
||||||
fi
|
|
||||||
if [[ "$version" == "10" ]]; then
|
|
||||||
# This adds timestamp and an optional comment field to the client table
|
|
||||||
# These fields are only temporary and will be replaces by the columns
|
|
||||||
# defined in gravity.db.sql during gravity swapping. We add them here
|
|
||||||
# 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 -ni "${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 -ni "${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 -ni "${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 -ni "${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 -ni "${database}" < "${scriptPath}/14_to_15.sql"
|
|
||||||
version=15
|
|
||||||
fi
|
|
||||||
if [[ "$version" == "15" ]]; then
|
|
||||||
# Add column abp_entries to adlist table
|
|
||||||
echo -e " ${INFO} Upgrading gravity database from version 15 to 16"
|
|
||||||
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/15_to_16.sql"
|
|
||||||
version=16
|
|
||||||
fi
|
|
||||||
if [[ "$version" == "16" ]]; then
|
|
||||||
# Add antigravity table
|
|
||||||
# Add column type to adlist table (to support adlist types)
|
|
||||||
echo -e " ${INFO} Upgrading gravity database from version 16 to 17"
|
|
||||||
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/16_to_17.sql"
|
|
||||||
version=17
|
|
||||||
fi
|
|
||||||
if [[ "$version" == "17" ]]; then
|
|
||||||
# Add adlist.id to vw_gravity and vw_antigravity
|
|
||||||
echo -e " ${INFO} Upgrading gravity database from version 17 to 18"
|
|
||||||
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/17_to_18.sql"
|
|
||||||
version=18
|
|
||||||
fi
|
|
||||||
if [[ "$version" == "18" ]]; then
|
|
||||||
# Modify DELETE triggers to delete BEFORE instead of AFTER to prevent
|
|
||||||
# foreign key constraint violations
|
|
||||||
echo -e " ${INFO} Upgrading gravity database from version 18 to 19"
|
|
||||||
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/18_to_19.sql"
|
|
||||||
version=19
|
|
||||||
fi
|
|
||||||
if [[ "$version" == "19" ]]; then
|
|
||||||
# Update views to use new allowlist/denylist names
|
|
||||||
echo -e " ${INFO} Upgrading gravity database from version 19 to 20"
|
|
||||||
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/19_to_20.sql"
|
|
||||||
version=20
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
ALTER TABLE client ADD COLUMN date_added INTEGER;
|
|
||||||
ALTER TABLE client ADD COLUMN date_modified INTEGER;
|
|
||||||
ALTER TABLE client ADD COLUMN comment TEXT;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_client_update AFTER UPDATE ON client
|
|
||||||
BEGIN
|
|
||||||
UPDATE client SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
UPDATE info SET value = 11 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
UPDATE "group" SET name = 'Default' WHERE id = 0;
|
|
||||||
UPDATE "group" SET description = 'The default group' WHERE id = 0;
|
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS tr_group_zero;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_group_zero AFTER DELETE ON "group"
|
|
||||||
BEGIN
|
|
||||||
INSERT OR IGNORE INTO "group" (id,enabled,name,description) VALUES (0,1,'Default','The default group');
|
|
||||||
END;
|
|
||||||
|
|
||||||
UPDATE info SET value = 12 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -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,11 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
ALTER TABLE adlist ADD COLUMN abp_entries INTEGER NOT NULL DEFAULT 0;
|
|
||||||
|
|
||||||
UPDATE info SET value = 16 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
ALTER TABLE adlist ADD COLUMN type INTEGER NOT NULL DEFAULT 0;
|
|
||||||
|
|
||||||
UPDATE adlist SET type = 0;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS antigravity
|
|
||||||
(
|
|
||||||
domain TEXT NOT NULL,
|
|
||||||
adlist_id INTEGER NOT NULL REFERENCES adlist (id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE VIEW vw_antigravity AS SELECT domain, adlist_by_group.group_id AS group_id
|
|
||||||
FROM antigravity
|
|
||||||
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = antigravity.adlist_id
|
|
||||||
LEFT JOIN adlist ON adlist.id = antigravity.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) AND adlist.type = 1;
|
|
||||||
|
|
||||||
DROP VIEW vw_adlist;
|
|
||||||
|
|
||||||
CREATE VIEW vw_adlist AS SELECT DISTINCT address, id, type
|
|
||||||
FROM adlist
|
|
||||||
WHERE enabled = 1
|
|
||||||
ORDER BY id;
|
|
||||||
|
|
||||||
UPDATE info SET value = 17 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
DROP VIEW vw_gravity;
|
|
||||||
CREATE VIEW vw_gravity AS SELECT domain, adlist.id AS adlist_id, adlist_by_group.group_id AS group_id
|
|
||||||
FROM gravity
|
|
||||||
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = gravity.adlist_id
|
|
||||||
LEFT JOIN adlist ON adlist.id = gravity.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);
|
|
||||||
|
|
||||||
DROP VIEW vw_antigravity;
|
|
||||||
CREATE VIEW vw_antigravity AS SELECT domain, adlist.id AS adlist_id, adlist_by_group.group_id AS group_id
|
|
||||||
FROM antigravity
|
|
||||||
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = antigravity.adlist_id
|
|
||||||
LEFT JOIN adlist ON adlist.id = antigravity.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) AND adlist.type = 1;
|
|
||||||
|
|
||||||
UPDATE info SET value = 18 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
DROP TRIGGER tr_domainlist_delete;
|
|
||||||
CREATE TRIGGER tr_domainlist_delete BEFORE DELETE ON domainlist
|
|
||||||
BEGIN
|
|
||||||
DELETE FROM domainlist_by_group WHERE domainlist_id = OLD.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
DROP TRIGGER tr_adlist_delete;
|
|
||||||
CREATE TRIGGER tr_adlist_delete BEFORE DELETE ON adlist
|
|
||||||
BEGIN
|
|
||||||
DELETE FROM adlist_by_group WHERE adlist_id = OLD.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
DROP TRIGGER tr_client_delete;
|
|
||||||
CREATE TRIGGER tr_client_delete BEFORE DELETE ON client
|
|
||||||
BEGIN
|
|
||||||
DELETE FROM client_by_group WHERE client_id = OLD.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
UPDATE info SET value = 19 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
DROP VIEW vw_whitelist;
|
|
||||||
CREATE VIEW vw_allowlist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 0
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
DROP VIEW vw_blacklist;
|
|
||||||
CREATE VIEW vw_denylist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 1
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
DROP VIEW vw_regex_whitelist;
|
|
||||||
CREATE VIEW vw_regex_allowlist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 2
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
DROP VIEW vw_regex_blacklist;
|
|
||||||
CREATE VIEW vw_regex_denylist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 3
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
UPDATE info SET value = 20 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
.timeout 30000
|
.timeout 30000
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
CREATE TABLE domain_audit
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
domain TEXT UNIQUE NOT NULL,
|
||||||
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int))
|
||||||
|
);
|
||||||
|
|
||||||
UPDATE info SET value = 2 WHERE property = 'version';
|
UPDATE info SET value = 2 WHERE property = 'version';
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
ALTER TABLE regex RENAME TO regex_blacklist;
|
|
||||||
|
|
||||||
CREATE TABLE regex_blacklist_by_group
|
|
||||||
(
|
|
||||||
regex_blacklist_id INTEGER NOT NULL REFERENCES regex_blacklist (id),
|
|
||||||
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
|
||||||
PRIMARY KEY (regex_blacklist_id, group_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
INSERT INTO regex_blacklist_by_group SELECT * FROM regex_by_group;
|
|
||||||
DROP TABLE regex_by_group;
|
|
||||||
DROP VIEW vw_regex;
|
|
||||||
DROP TRIGGER tr_regex_update;
|
|
||||||
|
|
||||||
CREATE VIEW vw_regex_blacklist AS SELECT DISTINCT domain
|
|
||||||
FROM regex_blacklist
|
|
||||||
LEFT JOIN regex_blacklist_by_group ON regex_blacklist_by_group.regex_blacklist_id = regex_blacklist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = regex_blacklist_by_group.group_id
|
|
||||||
WHERE regex_blacklist.enabled = 1 AND (regex_blacklist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
ORDER BY regex_blacklist.id;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_regex_blacklist_update AFTER UPDATE ON regex_blacklist
|
|
||||||
BEGIN
|
|
||||||
UPDATE regex_blacklist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE domain = NEW.domain;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TABLE regex_whitelist
|
|
||||||
(
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
domain TEXT UNIQUE NOT NULL,
|
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE regex_whitelist_by_group
|
|
||||||
(
|
|
||||||
regex_whitelist_id INTEGER NOT NULL REFERENCES regex_whitelist (id),
|
|
||||||
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
|
||||||
PRIMARY KEY (regex_whitelist_id, group_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE VIEW vw_regex_whitelist AS SELECT DISTINCT domain
|
|
||||||
FROM regex_whitelist
|
|
||||||
LEFT JOIN regex_whitelist_by_group ON regex_whitelist_by_group.regex_whitelist_id = regex_whitelist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = regex_whitelist_by_group.group_id
|
|
||||||
WHERE regex_whitelist.enabled = 1 AND (regex_whitelist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
ORDER BY regex_whitelist.id;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_regex_whitelist_update AFTER UPDATE ON regex_whitelist
|
|
||||||
BEGIN
|
|
||||||
UPDATE regex_whitelist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE domain = NEW.domain;
|
|
||||||
END;
|
|
||||||
|
|
||||||
|
|
||||||
UPDATE info SET value = 3 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
CREATE TABLE domainlist
|
|
||||||
(
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
type INTEGER NOT NULL DEFAULT 0,
|
|
||||||
domain TEXT UNIQUE NOT NULL,
|
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
ALTER TABLE whitelist ADD COLUMN type INTEGER;
|
|
||||||
UPDATE whitelist SET type = 0;
|
|
||||||
INSERT INTO domainlist (type,domain,enabled,date_added,date_modified,comment)
|
|
||||||
SELECT type,domain,enabled,date_added,date_modified,comment FROM whitelist;
|
|
||||||
|
|
||||||
ALTER TABLE blacklist ADD COLUMN type INTEGER;
|
|
||||||
UPDATE blacklist SET type = 1;
|
|
||||||
INSERT INTO domainlist (type,domain,enabled,date_added,date_modified,comment)
|
|
||||||
SELECT type,domain,enabled,date_added,date_modified,comment FROM blacklist;
|
|
||||||
|
|
||||||
ALTER TABLE regex_whitelist ADD COLUMN type INTEGER;
|
|
||||||
UPDATE regex_whitelist SET type = 2;
|
|
||||||
INSERT INTO domainlist (type,domain,enabled,date_added,date_modified,comment)
|
|
||||||
SELECT type,domain,enabled,date_added,date_modified,comment FROM regex_whitelist;
|
|
||||||
|
|
||||||
ALTER TABLE regex_blacklist ADD COLUMN type INTEGER;
|
|
||||||
UPDATE regex_blacklist SET type = 3;
|
|
||||||
INSERT INTO domainlist (type,domain,enabled,date_added,date_modified,comment)
|
|
||||||
SELECT type,domain,enabled,date_added,date_modified,comment FROM regex_blacklist;
|
|
||||||
|
|
||||||
DROP TABLE whitelist_by_group;
|
|
||||||
DROP TABLE blacklist_by_group;
|
|
||||||
DROP TABLE regex_whitelist_by_group;
|
|
||||||
DROP TABLE regex_blacklist_by_group;
|
|
||||||
CREATE TABLE domainlist_by_group
|
|
||||||
(
|
|
||||||
domainlist_id INTEGER NOT NULL REFERENCES domainlist (id),
|
|
||||||
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
|
||||||
PRIMARY KEY (domainlist_id, group_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
DROP TRIGGER tr_whitelist_update;
|
|
||||||
DROP TRIGGER tr_blacklist_update;
|
|
||||||
DROP TRIGGER tr_regex_whitelist_update;
|
|
||||||
DROP TRIGGER tr_regex_blacklist_update;
|
|
||||||
CREATE TRIGGER tr_domainlist_update AFTER UPDATE ON domainlist
|
|
||||||
BEGIN
|
|
||||||
UPDATE domainlist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE domain = NEW.domain;
|
|
||||||
END;
|
|
||||||
|
|
||||||
DROP VIEW vw_whitelist;
|
|
||||||
CREATE VIEW vw_whitelist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 0
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
DROP VIEW vw_blacklist;
|
|
||||||
CREATE VIEW vw_blacklist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 1
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
DROP VIEW vw_regex_whitelist;
|
|
||||||
CREATE VIEW vw_regex_whitelist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 2
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
DROP VIEW vw_regex_blacklist;
|
|
||||||
CREATE VIEW vw_regex_blacklist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 3
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
UPDATE info SET value = 4 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
DROP TABLE gravity;
|
|
||||||
CREATE TABLE gravity
|
|
||||||
(
|
|
||||||
domain TEXT NOT NULL,
|
|
||||||
adlist_id INTEGER NOT NULL REFERENCES adlist (id),
|
|
||||||
PRIMARY KEY(domain, adlist_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
DROP VIEW vw_gravity;
|
|
||||||
CREATE VIEW vw_gravity AS SELECT domain, adlist_by_group.group_id AS group_id
|
|
||||||
FROM gravity
|
|
||||||
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = gravity.adlist_id
|
|
||||||
LEFT JOIN adlist ON adlist.id = gravity.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);
|
|
||||||
|
|
||||||
CREATE TABLE client
|
|
||||||
(
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
ip TEXT NOL NULL UNIQUE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE client_by_group
|
|
||||||
(
|
|
||||||
client_id INTEGER NOT NULL REFERENCES client (id),
|
|
||||||
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
|
||||||
PRIMARY KEY (client_id, group_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
UPDATE info SET value = 5 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
DROP VIEW vw_adlist;
|
|
||||||
CREATE VIEW vw_adlist AS SELECT DISTINCT address, adlist.id AS id
|
|
||||||
FROM adlist
|
|
||||||
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = adlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = adlist_by_group.group_id
|
|
||||||
WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
ORDER BY adlist.id;
|
|
||||||
|
|
||||||
UPDATE info SET value = 6 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
INSERT OR REPLACE INTO "group" (id,enabled,name) VALUES (0,1,'Unassociated');
|
|
||||||
|
|
||||||
INSERT INTO domainlist_by_group (domainlist_id, group_id) SELECT id, 0 FROM domainlist;
|
|
||||||
INSERT INTO client_by_group (client_id, group_id) SELECT id, 0 FROM client;
|
|
||||||
INSERT INTO adlist_by_group (adlist_id, group_id) SELECT id, 0 FROM adlist;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_domainlist_add AFTER INSERT ON domainlist
|
|
||||||
BEGIN
|
|
||||||
INSERT INTO domainlist_by_group (domainlist_id, group_id) VALUES (NEW.id, 0);
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_client_add AFTER INSERT ON client
|
|
||||||
BEGIN
|
|
||||||
INSERT INTO client_by_group (client_id, group_id) VALUES (NEW.id, 0);
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_adlist_add AFTER INSERT ON adlist
|
|
||||||
BEGIN
|
|
||||||
INSERT INTO adlist_by_group (adlist_id, group_id) VALUES (NEW.id, 0);
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_group_zero AFTER DELETE ON "group"
|
|
||||||
BEGIN
|
|
||||||
INSERT OR REPLACE INTO "group" (id,enabled,name) VALUES (0,1,'Unassociated');
|
|
||||||
END;
|
|
||||||
|
|
||||||
UPDATE info SET value = 7 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
ALTER TABLE "group" RENAME TO "group__";
|
|
||||||
|
|
||||||
CREATE TABLE "group"
|
|
||||||
(
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
enabled BOOLEAN NOT NULL DEFAULT 1,
|
|
||||||
name TEXT UNIQUE NOT NULL,
|
|
||||||
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
|
||||||
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
|
||||||
description TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_group_update AFTER UPDATE ON "group"
|
|
||||||
BEGIN
|
|
||||||
UPDATE "group" SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO "group" (id,enabled,name,description) SELECT id,enabled,name,description FROM "group__";
|
|
||||||
|
|
||||||
DROP TABLE "group__";
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_group_zero AFTER DELETE ON "group"
|
|
||||||
BEGIN
|
|
||||||
INSERT OR IGNORE INTO "group" (id,enabled,name) VALUES (0,1,'Unassociated');
|
|
||||||
END;
|
|
||||||
|
|
||||||
UPDATE info SET value = 8 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS tr_group_update;
|
|
||||||
DROP TRIGGER IF EXISTS tr_group_zero;
|
|
||||||
|
|
||||||
PRAGMA legacy_alter_table=ON;
|
|
||||||
ALTER TABLE "group" RENAME TO "group__";
|
|
||||||
PRAGMA legacy_alter_table=OFF;
|
|
||||||
ALTER TABLE "group__" RENAME TO "group";
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_group_update AFTER UPDATE ON "group"
|
|
||||||
BEGIN
|
|
||||||
UPDATE "group" SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_group_zero AFTER DELETE ON "group"
|
|
||||||
BEGIN
|
|
||||||
INSERT OR IGNORE INTO "group" (id,enabled,name) VALUES (0,1,'Unassociated');
|
|
||||||
END;
|
|
||||||
|
|
||||||
UPDATE info SET value = 9 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
PRAGMA FOREIGN_KEYS=OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS whitelist;
|
|
||||||
DROP TABLE IF EXISTS blacklist;
|
|
||||||
DROP TABLE IF EXISTS regex_whitelist;
|
|
||||||
DROP TABLE IF EXISTS regex_blacklist;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_domainlist_delete AFTER DELETE ON domainlist
|
|
||||||
BEGIN
|
|
||||||
DELETE FROM domainlist_by_group WHERE domainlist_id = OLD.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_adlist_delete AFTER DELETE ON adlist
|
|
||||||
BEGIN
|
|
||||||
DELETE FROM adlist_by_group WHERE adlist_id = OLD.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_client_delete AFTER DELETE ON client
|
|
||||||
BEGIN
|
|
||||||
DELETE FROM client_by_group WHERE client_id = OLD.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
UPDATE info SET value = 10 WHERE property = 'version';
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,229 +1,246 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Pi-hole: A black hole for Internet advertisements
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
# Network-wide ad blocking via your own hardware.
|
# Network-wide ad blocking via your own hardware.
|
||||||
#
|
#
|
||||||
# allowlist and denylist domains
|
# Whitelist and blacklist domains
|
||||||
#
|
#
|
||||||
# This file is copyright under the latest version of the EUPL.
|
# This file is copyright under the latest version of the EUPL.
|
||||||
# Please see LICENSE file for your rights under this license.
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
# Globals
|
||||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
basename=pihole
|
||||||
# shellcheck source="./advanced/Scripts/utils.sh"
|
piholeDir=/etc/"${basename}"
|
||||||
source "${utilsfile}"
|
gravityDBfile="${piholeDir}/gravity.db"
|
||||||
|
|
||||||
apifile="${PI_HOLE_SCRIPT_DIR}/api.sh"
|
|
||||||
# shellcheck source="./advanced/Scripts/api.sh"
|
|
||||||
source "${apifile}"
|
|
||||||
|
|
||||||
# Determine database location
|
|
||||||
DBFILE=$(getFTLConfigValue "files.database")
|
|
||||||
if [ -z "$DBFILE" ]; then
|
|
||||||
DBFILE="/etc/pihole/pihole-FTL.db"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Determine gravity database location
|
|
||||||
GRAVITYDB=$(getFTLConfigValue "files.gravity")
|
|
||||||
if [ -z "$GRAVITYDB" ]; then
|
|
||||||
GRAVITYDB="/etc/pihole/gravity.db"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
reload=false
|
||||||
addmode=true
|
addmode=true
|
||||||
verbose=true
|
verbose=true
|
||||||
wildcard=false
|
wildcard=false
|
||||||
|
web=false
|
||||||
|
|
||||||
domList=()
|
domList=()
|
||||||
|
|
||||||
typeId=""
|
listType=""
|
||||||
comment=""
|
listname=""
|
||||||
|
|
||||||
colfile="/opt/pihole/COL_TABLE"
|
colfile="/opt/pihole/COL_TABLE"
|
||||||
# shellcheck source="./advanced/Scripts/COL_TABLE"
|
|
||||||
source ${colfile}
|
source ${colfile}
|
||||||
|
|
||||||
|
|
||||||
helpFunc() {
|
helpFunc() {
|
||||||
echo "Usage: pihole ${abbrv} [options] <domain> <domain2 ...>
|
if [[ "${listType}" == "whitelist" ]]; then
|
||||||
Example: 'pihole ${abbrv} site.com', or 'pihole ${abbrv} site1.com site2.com'
|
param="w"
|
||||||
${typeId^} one or more ${kindId} domains
|
type="whitelist"
|
||||||
|
elif [[ "${listType}" == "regex" && "${wildcard}" == true ]]; then
|
||||||
|
param="-wild"
|
||||||
|
type="wildcard blacklist"
|
||||||
|
elif [[ "${listType}" == "regex" ]]; then
|
||||||
|
param="-regex"
|
||||||
|
type="regex filter"
|
||||||
|
else
|
||||||
|
param="b"
|
||||||
|
type="blacklist"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Usage: pihole -${param} [options] <domain> <domain2 ...>
|
||||||
|
Example: 'pihole -${param} site.com', or 'pihole -${param} site1.com site2.com'
|
||||||
|
${type^} one or more domains
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
remove, delete, -d Remove domain(s)
|
-d, --delmode Remove domain(s) from the ${type}
|
||||||
|
-nr, --noreload Update ${type} without reloading the DNS server
|
||||||
-q, --quiet Make output less verbose
|
-q, --quiet Make output less verbose
|
||||||
-h, --help Show this help dialog
|
-h, --help Show this help dialog
|
||||||
-l, --list Display domains
|
-l, --list Display all your ${type}listed domains
|
||||||
--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
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateDomainList() {
|
EscapeRegexp() {
|
||||||
# Format domain into regex filter if requested
|
# This way we may safely insert an arbitrary
|
||||||
local dom=${1}
|
# string in our regular expressions
|
||||||
if [[ "${wildcard}" == true ]]; then
|
# This sed is intentionally executed in three steps to ease maintainability
|
||||||
dom="(\\.|^)${dom//\./\\.}$"
|
# The first sed removes any amount of leading dots
|
||||||
|
echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g"
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleOther() {
|
||||||
|
# Convert to lowercase
|
||||||
|
domain="${1,,}"
|
||||||
|
|
||||||
|
# Check validity of domain (don't check for regex entries)
|
||||||
|
if [[ "${#domain}" -le 253 ]]; then
|
||||||
|
if [[ "${listType}" == "regex" && "${wildcard}" == false ]]; then
|
||||||
|
validDomain="${domain}"
|
||||||
|
else
|
||||||
|
validDomain=$(grep -P "^((-|_)*[a-z\\d]((-|_)*[a-z\\d])*(-|_)*)(\\.(-|_)*([a-z\\d]((-|_)*[a-z\\d])*))*$" <<< "${domain}") # Valid chars check
|
||||||
|
validDomain=$(grep -P "^[^\\.]{1,63}(\\.[^\\.]{1,63})*$" <<< "${validDomain}") # Length of each label
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
domList=("${domList[@]}" "${dom}")
|
|
||||||
|
if [[ -n "${validDomain}" ]]; then
|
||||||
|
domList=("${domList[@]}" ${validDomain})
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} ${domain} is not a valid argument or domain name!"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessDomainList() {
|
||||||
|
if [[ "${listType}" == "regex" ]]; then
|
||||||
|
# Regex filter list
|
||||||
|
listname="regex filters"
|
||||||
|
else
|
||||||
|
# Whitelist / Blacklist
|
||||||
|
listname="${listType}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for dom in "${domList[@]}"; do
|
||||||
|
# Format domain into regex filter if requested
|
||||||
|
if [[ "${wildcard}" == true ]]; then
|
||||||
|
dom="(^|\\.)${dom//\./\\.}$"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Logic: If addmode then add to desired list and remove from the other;
|
||||||
|
# if delmode then remove from desired list but do not add to the other
|
||||||
|
if ${addmode}; then
|
||||||
|
AddDomain "${dom}" "${listType}"
|
||||||
|
if [[ ! "${listType}" == "regex" ]]; then
|
||||||
|
RemoveDomain "${dom}" "${listAlt}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
RemoveDomain "${dom}" "${listType}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDomain() {
|
AddDomain() {
|
||||||
local json num data
|
local domain list num
|
||||||
|
# Use printf to escape domain. %q prints the argument in a form that can be reused as shell input
|
||||||
|
domain="$1"
|
||||||
|
list="$2"
|
||||||
|
|
||||||
# Authenticate with the API
|
# Is the domain in the list we want to add it to?
|
||||||
LoginAPI
|
num="$(sqlite3 "${gravityDBfile}" "SELECT COUNT(*) FROM ${list} WHERE domain = '${domain}';")"
|
||||||
|
|
||||||
# Prepare request to POST /api/domains/{type}/{kind}
|
if [[ "${num}" -ne 0 ]]; then
|
||||||
# Build JSON object of the following form
|
if [[ "${verbose}" == true ]]; then
|
||||||
# {
|
echo -e " ${INFO} ${1} already exists in ${listname}, no need to add!"
|
||||||
# "domain": [ <domains> ],
|
fi
|
||||||
# "comment": <comment>
|
return
|
||||||
# }
|
|
||||||
# where <domains> is an array of domain strings and <comment> is a string
|
|
||||||
# We use jq to build the JSON object
|
|
||||||
json=$(jq --null-input --compact-output --arg domains "${domList[*]}" --arg comment "${comment}" '{domain: $domains | split(" "), comment: $comment}')
|
|
||||||
|
|
||||||
# Send the request
|
|
||||||
data=$(PostFTLData "domains/${typeId}/${kindId}" "${json}")
|
|
||||||
|
|
||||||
# Display domain(s) added
|
|
||||||
# (they are listed in .processed.success, use jq)
|
|
||||||
num=$(echo "${data}" | jq '.processed.success | length')
|
|
||||||
if [[ "${num}" -gt 0 ]] && [[ "${verbose}" == true ]]; then
|
|
||||||
echo -e " ${TICK} Added ${num} domain(s):"
|
|
||||||
for i in $(seq 0 $((num-1))); do
|
|
||||||
echo -e " - ${COL_BLUE}$(echo "${data}" | jq --raw-output ".processed.success[$i].item")${COL_NC}"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
# Display failed domain(s)
|
|
||||||
# (they are listed in .processed.errors, use jq)
|
|
||||||
num=$(echo "${data}" | jq '.processed.errors | length')
|
|
||||||
if [[ "${num}" -gt 0 ]] && [[ "${verbose}" == true ]]; then
|
|
||||||
echo -e " ${CROSS} Failed to add ${num} domain(s):"
|
|
||||||
for i in $(seq 0 $((num-1))); do
|
|
||||||
echo -e " - ${COL_BLUE}$(echo "${data}" | jq --raw-output ".processed.errors[$i].item")${COL_NC}"
|
|
||||||
error=$(echo "${data}" | jq --raw-output ".processed.errors[$i].error")
|
|
||||||
if [[ "${error}" == "UNIQUE constraint failed: domainlist.domain, domainlist.type" ]]; then
|
|
||||||
error="Domain already in the specified list"
|
|
||||||
fi
|
|
||||||
echo -e " ${error}"
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Log out
|
# Domain not found in the table, add it!
|
||||||
LogoutAPI
|
if [[ "${verbose}" == true ]]; then
|
||||||
|
echo -e " ${INFO} Adding ${1} to the ${listname}..."
|
||||||
|
fi
|
||||||
|
reload=true
|
||||||
|
# Insert only the domain here. The enabled and date_added fields will be filled
|
||||||
|
# with their default values (enabled = true, date_added = current timestamp)
|
||||||
|
sqlite3 "${gravityDBfile}" "INSERT INTO ${list} (domain) VALUES ('${domain}');"
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveDomain() {
|
RemoveDomain() {
|
||||||
local json num data status
|
local domain list num
|
||||||
|
# Use printf to escape domain. %q prints the argument in a form that can be reused as shell input
|
||||||
|
domain="$1"
|
||||||
|
list="$2"
|
||||||
|
|
||||||
# Authenticate with the API
|
# Is the domain in the list we want to remove it from?
|
||||||
LoginAPI
|
num="$(sqlite3 "${gravityDBfile}" "SELECT COUNT(*) FROM ${list} WHERE domain = '${domain}';")"
|
||||||
|
|
||||||
# Prepare request to POST /api/domains:batchDelete
|
if [[ "${num}" -eq 0 ]]; then
|
||||||
# Build JSON object of the following form
|
if [[ "${verbose}" == true ]]; then
|
||||||
# [{
|
echo -e " ${INFO} ${1} does not exist in ${list}, no need to remove!"
|
||||||
# "item": <domain>,
|
fi
|
||||||
# "type": "${typeId}",
|
return
|
||||||
# "kind": "${kindId}",
|
|
||||||
# }]
|
|
||||||
# where <domain> is the domain string and ${typeId} and ${kindId} are the type and kind IDs
|
|
||||||
# We use jq to build the JSON object)
|
|
||||||
json=$(jq --null-input --compact-output --arg domains "${domList[*]}" --arg typeId "${typeId}" --arg kindId "${kindId}" '[ $domains | split(" ")[] as $item | {item: $item, type: $typeId, kind: $kindId} ]')
|
|
||||||
|
|
||||||
# Send the request
|
|
||||||
data=$(PostFTLData "domains:batchDelete" "${json}" "status")
|
|
||||||
# Separate the status from the data
|
|
||||||
status=$(printf %s "${data#"${data%???}"}")
|
|
||||||
data=$(printf %s "${data%???}")
|
|
||||||
|
|
||||||
# If there is an .error object in the returned data, display it
|
|
||||||
local error
|
|
||||||
error=$(jq --compact-output <<< "${data}" '.error')
|
|
||||||
if [[ $error != "null" && $error != "" ]]; then
|
|
||||||
echo -e " ${CROSS} Failed to remove domain(s):"
|
|
||||||
echo -e " $(jq <<< "${data}" '.error')"
|
|
||||||
elif [[ "${verbose}" == true && "${status}" == "204" ]]; then
|
|
||||||
echo -e " ${TICK} Domain(s) removed from the ${kindId} ${typeId}list"
|
|
||||||
elif [[ "${verbose}" == true && "${status}" == "404" ]]; then
|
|
||||||
echo -e " ${TICK} Requested domain(s) not found on ${kindId} ${typeId}list"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Log out
|
# Domain found in the table, remove it!
|
||||||
LogoutAPI
|
if [[ "${verbose}" == true ]]; then
|
||||||
|
echo -e " ${INFO} Removing ${1} from the ${listname}..."
|
||||||
|
fi
|
||||||
|
reload=true
|
||||||
|
# Remove it from the current list
|
||||||
|
sqlite3 "${gravityDBfile}" "DELETE FROM ${list} WHERE domain = '${domain}';"
|
||||||
}
|
}
|
||||||
|
|
||||||
Displaylist() {
|
Displaylist() {
|
||||||
local data
|
local list listname count num_pipes domain enabled status nicedate
|
||||||
|
|
||||||
# if either typeId or kindId is empty, we cannot display the list
|
listname="${listType}"
|
||||||
if [[ -z "${typeId}" ]] || [[ -z "${kindId}" ]]; then
|
data="$(sqlite3 "${gravityDBfile}" "SELECT domain,enabled,date_modified FROM ${listType};" 2> /dev/null)"
|
||||||
echo " ${CROSS} Unable to display list. Please specify a list type and kind."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Authenticate with the API
|
if [[ -z $data ]]; then
|
||||||
LoginAPI
|
echo -e "Not showing empty ${listname}"
|
||||||
|
|
||||||
# Send the request
|
|
||||||
data=$(GetFTLData "domains/${typeId}/${kindId}")
|
|
||||||
|
|
||||||
# Display the list
|
|
||||||
num=$(echo "${data}" | jq '.domains | length')
|
|
||||||
if [[ "${num}" -gt 0 ]]; then
|
|
||||||
echo -e " ${TICK} Found ${num} domain(s) in the ${kindId} ${typeId}list:"
|
|
||||||
for i in $(seq 0 $((num-1))); do
|
|
||||||
echo -e " - ${COL_BLUE}$(echo "${data}" | jq --compact-output ".domains[$i].domain")${COL_NC}"
|
|
||||||
echo -e " Comment: $(echo "${data}" | jq --compact-output ".domains[$i].comment")"
|
|
||||||
echo -e " Groups: $(echo "${data}" | jq --compact-output ".domains[$i].groups")"
|
|
||||||
echo -e " Added: $(date -d @"$(echo "${data}" | jq --compact-output ".domains[$i].date_added")")"
|
|
||||||
echo -e " Last modified: $(date -d @"$(echo "${data}" | jq --compact-output ".domains[$i].date_modified")")"
|
|
||||||
done
|
|
||||||
else
|
else
|
||||||
echo -e " ${INFO} No domains found in the ${kindId} ${typeId}list"
|
echo -e "Displaying ${listname}:"
|
||||||
|
count=1
|
||||||
|
while IFS= read -r line
|
||||||
|
do
|
||||||
|
# Count number of pipes seen in this line
|
||||||
|
# This is necessary because we can only detect the pipe separating the fields
|
||||||
|
# from the end backwards as the domain (which is the first field) may contain
|
||||||
|
# pipe symbols as they are perfectly valid regex filter control characters
|
||||||
|
num_pipes="$(grep -c "^" <<< "$(grep -o "|" <<< "${line}")")"
|
||||||
|
|
||||||
|
# Extract domain and enabled status based on the obtained number of pipe characters
|
||||||
|
domain="$(cut -d'|' -f"-$((num_pipes-1))" <<< "${line}")"
|
||||||
|
enabled="$(cut -d'|' -f"$((num_pipes))" <<< "${line}")"
|
||||||
|
datemod="$(cut -d'|' -f"$((num_pipes+1))" <<< "${line}")"
|
||||||
|
|
||||||
|
# Translate boolean status into human readable string
|
||||||
|
if [[ "${enabled}" -eq 1 ]]; then
|
||||||
|
status="enabled"
|
||||||
|
else
|
||||||
|
status="disabled"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get nice representation of numerical date stored in database
|
||||||
|
nicedate=$(date --rfc-2822 -d "@${datemod}")
|
||||||
|
|
||||||
|
echo " ${count}: ${domain} (${status}, last modified ${nicedate})"
|
||||||
|
count=$((count+1))
|
||||||
|
done <<< "${data}"
|
||||||
fi
|
fi
|
||||||
|
exit 0;
|
||||||
# Log out
|
|
||||||
LogoutAPI
|
|
||||||
|
|
||||||
# Return early without adding/deleting domains
|
|
||||||
exit 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GetComment() {
|
NukeList() {
|
||||||
comment="$1"
|
sqlite3 "${gravityDBfile}" "DELETE FROM ${listType};"
|
||||||
if [[ "${comment}" =~ [^a-zA-Z0-9_\#:/\.,\ -] ]]; then
|
|
||||||
echo " ${CROSS} Found invalid characters in domain comment!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (( "$#" )); do
|
for var in "$@"; do
|
||||||
case "${1}" in
|
case "${var}" in
|
||||||
"allow" | "allowlist" ) kindId="exact"; typeId="allow"; abbrv="allow";;
|
"-w" | "whitelist" ) listType="whitelist"; listAlt="blacklist";;
|
||||||
"deny" | "denylist" ) kindId="exact"; typeId="deny"; abbrv="deny";;
|
"-b" | "blacklist" ) listType="blacklist"; listAlt="whitelist";;
|
||||||
"--allow-regex" | "allow-regex" ) kindId="regex"; typeId="allow"; abbrv="--allow-regex";;
|
"--wild" | "wildcard" ) listType="regex"; wildcard=true;;
|
||||||
"--allow-wild" | "allow-wild" ) kindId="regex"; typeId="allow"; wildcard=true; abbrv="--allow-wild";;
|
"--regex" | "regex" ) listType="regex";;
|
||||||
"--regex" | "regex" ) kindId="regex"; typeId="deny"; abbrv="--regex";;
|
"-nr"| "--noreload" ) reload=false;;
|
||||||
"--wild" | "wildcard" ) kindId="regex"; typeId="deny"; wildcard=true; abbrv="--wild";;
|
"-d" | "--delmode" ) addmode=false;;
|
||||||
"-d" | "remove" | "delete" ) addmode=false;;
|
|
||||||
"-q" | "--quiet" ) verbose=false;;
|
"-q" | "--quiet" ) verbose=false;;
|
||||||
"-h" | "--help" ) helpFunc;;
|
"-h" | "--help" ) helpFunc;;
|
||||||
"-l" | "--list" ) Displaylist;;
|
"-l" | "--list" ) Displaylist;;
|
||||||
"--comment" ) GetComment "${2}"; shift;;
|
"--nuke" ) NukeList;;
|
||||||
* ) CreateDomainList "${1}";;
|
"--web" ) web=true;;
|
||||||
|
* ) HandleOther "${var}";;
|
||||||
esac
|
esac
|
||||||
shift
|
|
||||||
done
|
done
|
||||||
|
|
||||||
shift
|
shift
|
||||||
|
|
||||||
if [[ ${#domList[@]} == 0 ]]; then
|
if [[ $# = 0 ]]; then
|
||||||
helpFunc
|
helpFunc
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ${addmode}; then
|
ProcessDomainList
|
||||||
AddDomain
|
|
||||||
else
|
# Used on web interface
|
||||||
RemoveDomain
|
if $web; then
|
||||||
|
echo "DONE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${reload}" != false ]]; then
|
||||||
|
pihole restartdns reload
|
||||||
fi
|
fi
|
||||||
|
|||||||
73
advanced/Scripts/piholeARPTable.sh
Executable file
73
advanced/Scripts/piholeARPTable.sh
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
|
||||||
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
|
# (c) 2019 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
# Network-wide ad blocking via your own hardware.
|
||||||
|
#
|
||||||
|
# ARP table interaction
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
coltable="/opt/pihole/COL_TABLE"
|
||||||
|
if [[ -f ${coltable} ]]; then
|
||||||
|
source ${coltable}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine database location
|
||||||
|
# Obtain DBFILE=... setting from pihole-FTL.db
|
||||||
|
# Constructed to return nothing when
|
||||||
|
# a) the setting is not present in the config file, or
|
||||||
|
# b) the setting is commented out (e.g. "#DBFILE=...")
|
||||||
|
FTLconf="/etc/pihole/pihole-FTL.conf"
|
||||||
|
if [ -e "$FTLconf" ]; then
|
||||||
|
DBFILE="$(sed -n -e 's/^\s*DBFILE\s*=\s*//p' ${FTLconf})"
|
||||||
|
fi
|
||||||
|
# Test for empty string. Use standard path in this case.
|
||||||
|
if [ -z "$DBFILE" ]; then
|
||||||
|
DBFILE="/etc/pihole/pihole-FTL.db"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
flushARP(){
|
||||||
|
local output
|
||||||
|
if [[ "${args[1]}" != "quiet" ]]; then
|
||||||
|
echo -ne " ${INFO} Flushing network table ..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Flush ARP cache to avoid re-adding of dead entries
|
||||||
|
if ! output=$(ip neigh flush all 2>&1); then
|
||||||
|
echo -e "${OVER} ${CROSS} Failed to clear ARP cache"
|
||||||
|
echo " Output: ${output}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Truncate network_addresses table in pihole-FTL.db
|
||||||
|
# This needs to be done before we can truncate the network table due to
|
||||||
|
# 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}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Truncate network table in pihole-FTL.db
|
||||||
|
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}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${args[1]}" != "quiet" ]]; then
|
||||||
|
echo -e "${OVER} ${TICK} Flushed network table"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
args=("$@")
|
||||||
|
|
||||||
|
case "${args[0]}" in
|
||||||
|
"arpflush" ) flushARP;;
|
||||||
|
esac
|
||||||
151
advanced/Scripts/piholeCheckout.sh
Executable file → Normal file
151
advanced/Scripts/piholeCheckout.sh
Executable file → Normal file
@@ -3,30 +3,32 @@
|
|||||||
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
# Network-wide ad blocking via your own hardware.
|
# Network-wide ad blocking via your own hardware.
|
||||||
#
|
#
|
||||||
# Switch Pi-hole subsystems to a different GitHub branch.
|
# Switch Pi-hole subsystems to a different Github branch.
|
||||||
#
|
#
|
||||||
# This file is copyright under the latest version of the EUPL.
|
# This file is copyright under the latest version of the EUPL.
|
||||||
# Please see LICENSE file for your rights under this license.
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||||
SKIP_INSTALL="true"
|
PH_TEST="true"
|
||||||
# shellcheck source="./automated install/basic-install.sh"
|
|
||||||
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||||
|
|
||||||
# webInterfaceGitUrl set in basic-install.sh
|
# webInterfaceGitUrl set in basic-install.sh
|
||||||
# webInterfaceDir set in basic-install.sh
|
# webInterfaceDir set in basic-install.sh
|
||||||
# piholeGitURL set in basic-install.sh
|
# piholeGitURL set in basic-install.sh
|
||||||
# is_repo() sourced from basic-install.sh
|
# is_repo() sourced from basic-install.sh
|
||||||
|
# setupVars set in basic-install.sh
|
||||||
# check_download_exists sourced from basic-install.sh
|
# check_download_exists sourced from basic-install.sh
|
||||||
# fully_fetch_repo sourced from basic-install.sh
|
# fully_fetch_repo sourced from basic-install.sh
|
||||||
# get_available_branches sourced from basic-install.sh
|
# get_available_branches sourced from basic-install.sh
|
||||||
# fetch_checkout_pull_branch sourced from basic-install.sh
|
# fetch_checkout_pull_branch sourced from basic-install.sh
|
||||||
# checkout_pull_branch sourced from basic-install.sh
|
# checkout_pull_branch sourced from basic-install.sh
|
||||||
|
|
||||||
|
source "${setupVars}"
|
||||||
|
|
||||||
warning1() {
|
warning1() {
|
||||||
echo " Please note that changing branches severely alters your Pi-hole subsystems"
|
echo " Please note that changing branches severely alters your Pi-hole subsystems"
|
||||||
echo " Features that work on the master branch, may not on a development branch"
|
echo " Features that work on the master branch, may not on a development branch"
|
||||||
echo -e " ${COL_RED}This feature is NOT supported unless a Pi-hole developer explicitly asks!${COL_NC}"
|
echo -e " ${COL_LIGHT_RED}This feature is NOT supported unless a Pi-hole developer explicitly asks!${COL_NC}"
|
||||||
read -r -p " Have you read and understood this? [y/N] " response
|
read -r -p " Have you read and understood this? [y/N] " response
|
||||||
case "${response}" in
|
case "${response}" in
|
||||||
[yY][eE][sS]|[yY])
|
[yY][eE][sS]|[yY])
|
||||||
@@ -34,56 +36,35 @@ warning1() {
|
|||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo -e "\\n ${INFO} Branch change has been canceled"
|
echo -e "\\n ${INFO} Branch change has been cancelled"
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
checkout() {
|
checkout() {
|
||||||
|
|
||||||
local skipFTL additionalFlag
|
|
||||||
skipFTL=false
|
|
||||||
# Check arguments
|
|
||||||
for var in "$@"; do
|
|
||||||
case "$var" in
|
|
||||||
"--skipFTL") skipFTL=true ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "${skipFTL}" == true ]; then
|
|
||||||
additionalFlag="--skipFTL"
|
|
||||||
else
|
|
||||||
additionalFlag=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
local corebranches
|
local corebranches
|
||||||
local webbranches
|
local webbranches
|
||||||
|
|
||||||
# Check if FTL is installed - do this early on as FTL is a hard dependency for Pi-hole
|
|
||||||
local funcOutput
|
|
||||||
funcOutput=$(get_binary_name) #Store output of get_binary_name here
|
|
||||||
local binary
|
|
||||||
binary="pihole-FTL${funcOutput##*pihole-FTL}" #binary name will be the last line of the output of get_binary_name (it always begins with pihole-FTL)
|
|
||||||
|
|
||||||
# Avoid globbing
|
# Avoid globbing
|
||||||
set -f
|
set -f
|
||||||
|
|
||||||
# This is unlikely
|
# This is unlikely
|
||||||
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||||
echo -e " ${COL_RED}Error: Core Pi-hole repo is missing from system!"
|
echo -e " ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!"
|
||||||
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
|
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == "true" ]]; then
|
||||||
if ! is_repo "${webInterfaceDir}" ; then
|
if ! is_repo "${webInterfaceDir}" ; then
|
||||||
echo -e " ${COL_RED}Error: Web Admin repo is missing from system!"
|
echo -e " ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!"
|
||||||
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
|
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
|
||||||
exit 1;
|
exit 1;
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "${1}" ]]; then
|
if [[ -z "${1}" ]]; then
|
||||||
echo -e " ${COL_RED}Invalid option${COL_NC}"
|
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}"
|
||||||
echo -e " Try 'pihole checkout --help' for more information."
|
echo -e " Try 'pihole checkout --help' for more information."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -94,27 +75,33 @@ checkout() {
|
|||||||
|
|
||||||
if [[ "${1}" == "dev" ]] ; then
|
if [[ "${1}" == "dev" ]] ; then
|
||||||
# Shortcut to check out development branches
|
# Shortcut to check out development branches
|
||||||
echo -e " ${INFO} Shortcut \"${COL_YELLOW}dev${COL_NC}\" detected - checking out development branches..."
|
echo -e " ${INFO} Shortcut \"dev\" detected - checking out development / devel branches..."
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${INFO} Pi-hole Core"
|
echo -e " ${INFO} Pi-hole Core"
|
||||||
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core development branch"; exit 1; }
|
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core developement branch"; exit 1; }
|
||||||
echo ""
|
if [[ "${INSTALL_WEB_INTERFACE}" == "true" ]]; then
|
||||||
echo -e " ${INFO} Web interface"
|
echo ""
|
||||||
fetch_checkout_pull_branch "${webInterfaceDir}" "development" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; }
|
echo -e " ${INFO} Web interface"
|
||||||
|
fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; }
|
||||||
|
fi
|
||||||
#echo -e " ${TICK} Pi-hole Core"
|
#echo -e " ${TICK} Pi-hole Core"
|
||||||
|
|
||||||
|
get_binary_name
|
||||||
local path
|
local path
|
||||||
path="development/${binary}"
|
path="development/${binary}"
|
||||||
echo "development" > /etc/pihole/ftlbranch
|
echo "development" > /etc/pihole/ftlbranch
|
||||||
chmod 644 /etc/pihole/ftlbranch
|
chmod 644 /etc/pihole/ftlbranch
|
||||||
elif [[ "${1}" == "master" ]] ; then
|
elif [[ "${1}" == "master" ]] ; then
|
||||||
# Shortcut to check out master branches
|
# Shortcut to check out master branches
|
||||||
echo -e " ${INFO} Shortcut \"${COL_YELLOW}master${COL_NC}\" detected - checking out master branches..."
|
echo -e " ${INFO} Shortcut \"master\" detected - checking out master branches..."
|
||||||
echo -e " ${INFO} Pi-hole core"
|
echo -e " ${INFO} Pi-hole core"
|
||||||
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "master" || { echo " ${CROSS} Unable to pull Core master branch"; exit 1; }
|
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "master" || { echo " ${CROSS} Unable to pull Core master branch"; exit 1; }
|
||||||
echo -e " ${INFO} Web interface"
|
if [[ ${INSTALL_WEB_INTERFACE} == "true" ]]; then
|
||||||
fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; }
|
echo -e " ${INFO} Web interface"
|
||||||
|
fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; }
|
||||||
|
fi
|
||||||
#echo -e " ${TICK} Web Interface"
|
#echo -e " ${TICK} Web Interface"
|
||||||
|
get_binary_name
|
||||||
local path
|
local path
|
||||||
path="master/${binary}"
|
path="master/${binary}"
|
||||||
echo "master" > /etc/pihole/ftlbranch
|
echo "master" > /etc/pihole/ftlbranch
|
||||||
@@ -126,7 +113,7 @@ checkout() {
|
|||||||
echo -e "${OVER} ${CROSS} $str"
|
echo -e "${OVER} ${CROSS} $str"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
mapfile -t corebranches < <(get_available_branches "${PI_HOLE_FILES_DIR}")
|
corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}"))
|
||||||
|
|
||||||
if [[ "${corebranches[*]}" == *"master"* ]]; then
|
if [[ "${corebranches[*]}" == *"master"* ]]; then
|
||||||
echo -e "${OVER} ${TICK} $str"
|
echo -e "${OVER} ${TICK} $str"
|
||||||
@@ -140,20 +127,20 @@ checkout() {
|
|||||||
echo ""
|
echo ""
|
||||||
# Have the user choose the branch they want
|
# Have the user choose the branch they want
|
||||||
if ! (for e in "${corebranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
|
if ! (for e in "${corebranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
|
||||||
echo -e " ${INFO} Requested branch \"${COL_CYAN}${2}${COL_NC}\" is not available"
|
echo -e " ${INFO} Requested branch \"${2}\" is not available"
|
||||||
echo -e " ${INFO} Available branches for Core are:"
|
echo -e " ${INFO} Available branches for Core are:"
|
||||||
for e in "${corebranches[@]}"; do echo " - $e"; done
|
for e in "${corebranches[@]}"; do echo " - $e"; done
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}"
|
checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}"
|
||||||
elif [[ "${1}" == "web" ]] ; then
|
elif [[ "${1}" == "web" ]] && [[ "${INSTALL_WEB_INTERFACE}" == "true" ]] ; then
|
||||||
str="Fetching branches from ${webInterfaceGitUrl}"
|
str="Fetching branches from ${webInterfaceGitUrl}"
|
||||||
echo -ne " ${INFO} $str"
|
echo -ne " ${INFO} $str"
|
||||||
if ! fully_fetch_repo "${webInterfaceDir}" ; then
|
if ! fully_fetch_repo "${webInterfaceDir}" ; then
|
||||||
echo -e "${OVER} ${CROSS} $str"
|
echo -e "${OVER} ${CROSS} $str"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
mapfile -t webbranches < <(get_available_branches "${webInterfaceDir}")
|
webbranches=($(get_available_branches "${webInterfaceDir}"))
|
||||||
|
|
||||||
if [[ "${webbranches[*]}" == *"master"* ]]; then
|
if [[ "${webbranches[*]}" == *"master"* ]]; then
|
||||||
echo -e "${OVER} ${TICK} $str"
|
echo -e "${OVER} ${TICK} $str"
|
||||||
@@ -167,94 +154,44 @@ checkout() {
|
|||||||
echo ""
|
echo ""
|
||||||
# Have the user choose the branch they want
|
# Have the user choose the branch they want
|
||||||
if ! (for e in "${webbranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
|
if ! (for e in "${webbranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
|
||||||
echo -e " ${INFO} Requested branch \"${COL_CYAN}${2}${COL_NC}\" is not available"
|
echo -e " ${INFO} Requested branch \"${2}\" is not available"
|
||||||
echo -e " ${INFO} Available branches for Web Admin are:"
|
echo -e " ${INFO} Available branches for Web Admin are:"
|
||||||
for e in "${webbranches[@]}"; do echo " - $e"; done
|
for e in "${webbranches[@]}"; do echo " - $e"; done
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
checkout_pull_branch "${webInterfaceDir}" "${2}"
|
checkout_pull_branch "${webInterfaceDir}" "${2}"
|
||||||
# Update local and remote versions via updatechecker
|
|
||||||
/opt/pihole/updatecheck.sh
|
|
||||||
elif [[ "${1}" == "ftl" ]] ; then
|
elif [[ "${1}" == "ftl" ]] ; then
|
||||||
|
get_binary_name
|
||||||
local path
|
local path
|
||||||
local oldbranch
|
|
||||||
local existing=false
|
|
||||||
path="${2}/${binary}"
|
path="${2}/${binary}"
|
||||||
oldbranch="$(pihole-FTL -b)"
|
|
||||||
|
|
||||||
# Check if requested branch is available
|
|
||||||
echo -e " ${INFO} Checking for availability of branch ${COL_CYAN}${2}${COL_NC} on GitHub"
|
|
||||||
mapfile -t ftlbranches < <(git ls-remote https://github.com/pi-hole/ftl | grep "refs/heads" | cut -d'/' -f3- -)
|
|
||||||
# If returned array is empty -> connectivity issue
|
|
||||||
if [[ ${#ftlbranches[@]} -eq 0 ]]; then
|
|
||||||
echo -e " ${CROSS} Unable to fetch branches from GitHub. Please check your Internet connection and try again later."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
for e in "${ftlbranches[@]}"; do [[ "$e" == "${2}" ]] && existing=true; done
|
|
||||||
if [[ "${existing}" == false ]]; then
|
|
||||||
echo -e " ${CROSS} Requested branch is not available\n"
|
|
||||||
echo -e " ${INFO} Available branches are:"
|
|
||||||
for e in "${ftlbranches[@]}"; do echo " - $e"; done
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo -e " ${TICK} Branch ${2} exists on GitHub"
|
|
||||||
|
|
||||||
echo -e " ${INFO} Checking for ${COL_YELLOW}${binary}${COL_NC} binary on https://ftl.pi-hole.net"
|
|
||||||
|
|
||||||
if check_download_exists "$path"; then
|
if check_download_exists "$path"; then
|
||||||
echo " ${TICK} Binary exists"
|
echo " ${TICK} Branch ${2} exists"
|
||||||
echo "${2}" > /etc/pihole/ftlbranch
|
echo "${2}" > /etc/pihole/ftlbranch
|
||||||
chmod 644 /etc/pihole/ftlbranch
|
chmod 644 /etc/pihole/ftlbranch
|
||||||
echo -e " ${INFO} Switching to branch: ${COL_CYAN}${2}${COL_NC} from ${COL_CYAN}${oldbranch}${COL_NC}"
|
|
||||||
FTLinstall "${binary}"
|
FTLinstall "${binary}"
|
||||||
restart_service pihole-FTL
|
restart_service pihole-FTL
|
||||||
enable_service pihole-FTL
|
enable_service pihole-FTL
|
||||||
str="Restarting FTL..."
|
|
||||||
echo -ne " ${INFO} ${str}"
|
|
||||||
# Wait until name resolution is working again after restarting FTL,
|
|
||||||
# so that the updatechecker can run successfully and does not fail
|
|
||||||
# trying to resolve github.com
|
|
||||||
until getent hosts github.com &> /dev/null; do
|
|
||||||
# Append one dot for each second waiting
|
|
||||||
str="${str}."
|
|
||||||
echo -ne " ${OVER} ${INFO} ${str}"
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
echo -e " ${OVER} ${TICK} Restarted FTL service"
|
|
||||||
|
|
||||||
# Update local and remote versions via updatechecker
|
|
||||||
/opt/pihole/updatecheck.sh
|
|
||||||
else
|
else
|
||||||
local status
|
echo " ${CROSS} Requested branch \"${2}\" is not available"
|
||||||
status=$?
|
ftlbranches=( $(git ls-remote https://github.com/pi-hole/ftl | grep 'heads' | sed 's/refs\/heads\///;s/ //g' | awk '{print $2}') )
|
||||||
if [ $status -eq 1 ]; then
|
echo -e " ${INFO} Available branches for FTL are:"
|
||||||
# Binary for requested branch is not available, may still be
|
for e in "${ftlbranches[@]}"; do echo " - $e"; done
|
||||||
# int he process of being built or CI build job failed
|
exit 1
|
||||||
printf " %b Binary for requested branch is not available, please try again later.\\n" "${CROSS}"
|
|
||||||
printf " If the issue persists, please contact Pi-hole Support and ask them to re-generate the binary.\\n"
|
|
||||||
exit 1
|
|
||||||
elif [ $status -eq 2 ]; then
|
|
||||||
printf " %b Unable to download from ftl.pi-hole.net. Please check your Internet connection and try again later.\\n" "${CROSS}"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
printf " %b Unknown checkout error. Please contact Pi-hole Support\\n" "${CROSS}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
echo -e " ${CROSS} Requested option \"${1}\" is not available"
|
echo -e " ${INFO} Requested option \"${1}\" is not available"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Force updating everything
|
# Force updating everything
|
||||||
if [[ ! "${1}" == "web" && ! "${1}" == "ftl" ]]; then
|
if [[ ! "${1}" == "web" && ! "${1}" == "ftl" ]]; then
|
||||||
echo -e " ${INFO} Running installer to upgrade your installation"
|
echo -e " ${INFO} Running installer to upgrade your installation"
|
||||||
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended ${additionalFlag}; then
|
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
|
||||||
exit 0
|
exit 0
|
||||||
else
|
else
|
||||||
echo -e " ${COL_RED} Error: Unable to complete update, please contact support${COL_NC}"
|
echo -e " ${COL_LIGHT_RED} Error: Unable to complete update, please contact support${COL_NC}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,68 +9,62 @@
|
|||||||
# Please see LICENSE file for your rights under this license.
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
colfile="/opt/pihole/COL_TABLE"
|
colfile="/opt/pihole/COL_TABLE"
|
||||||
# shellcheck source="./advanced/Scripts/COL_TABLE"
|
|
||||||
source ${colfile}
|
source ${colfile}
|
||||||
|
|
||||||
readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
|
||||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
|
||||||
# shellcheck source="./advanced/Scripts/utils.sh"
|
|
||||||
source "${utilsfile}"
|
|
||||||
|
|
||||||
# Determine database location
|
# Determine database location
|
||||||
DBFILE=$(getFTLConfigValue "files.database")
|
# Obtain DBFILE=... setting from pihole-FTL.db
|
||||||
|
# Constructed to return nothing when
|
||||||
|
# a) the setting is not present in the config file, or
|
||||||
|
# b) the setting is commented out (e.g. "#DBFILE=...")
|
||||||
|
FTLconf="/etc/pihole/pihole-FTL.conf"
|
||||||
|
if [ -e "$FTLconf" ]; then
|
||||||
|
DBFILE="$(sed -n -e 's/^\s*DBFILE\s*=\s*//p' ${FTLconf})"
|
||||||
|
fi
|
||||||
|
# Test for empty string. Use standard path in this case.
|
||||||
if [ -z "$DBFILE" ]; then
|
if [ -z "$DBFILE" ]; then
|
||||||
DBFILE="/etc/pihole/pihole-FTL.db"
|
DBFILE="/etc/pihole/pihole-FTL.db"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Determine log file location
|
if [[ "$@" != *"quiet"* ]]; then
|
||||||
LOGFILE=$(getFTLConfigValue "files.log.dnsmasq")
|
echo -ne " ${INFO} Flushing /var/log/pihole.log ..."
|
||||||
if [ -z "$LOGFILE" ]; then
|
|
||||||
LOGFILE="/var/log/pihole/pihole.log"
|
|
||||||
fi
|
fi
|
||||||
FTLFILE=$(getFTLConfigValue "files.log.ftl")
|
if [[ "$@" == *"once"* ]]; then
|
||||||
if [ -z "$FTLFILE" ]; then
|
# Nightly logrotation
|
||||||
FTLFILE="/var/log/pihole/FTL.log"
|
if command -v /usr/sbin/logrotate >/dev/null; then
|
||||||
fi
|
# Logrotate once
|
||||||
WEBFILE=$(getFTLConfigValue "files.log.webserver")
|
/usr/sbin/logrotate --force /etc/pihole/logrotate
|
||||||
if [ -z "$WEBFILE" ]; then
|
else
|
||||||
WEBFILE="/var/log/pihole/webserver.log"
|
# Copy pihole.log over to pihole.log.1
|
||||||
fi
|
# and empty out pihole.log
|
||||||
|
# Note that moving the file is not an option, as
|
||||||
# Helper function to handle log flushing for a single file
|
# dnsmasq would happily continue writing into the
|
||||||
flush_log() {
|
# moved file (it will have the same file handler)
|
||||||
local logfile="$1"
|
cp -p /var/log/pihole.log /var/log/pihole.log.1
|
||||||
if [[ "$*" != *"quiet"* ]]; then
|
echo " " > /var/log/pihole.log
|
||||||
echo -ne " ${INFO} Flushing ${logfile} ..."
|
chmod 644 /var/log/pihole.log
|
||||||
fi
|
fi
|
||||||
echo " " > "${logfile}"
|
else
|
||||||
chmod 640 "${logfile}"
|
# Manual flushing
|
||||||
if [ -f "${logfile}.1" ]; then
|
if command -v /usr/sbin/logrotate >/dev/null; then
|
||||||
echo " " > "${logfile}.1"
|
# Logrotate twice to move all data out of sight of FTL
|
||||||
chmod 640 "${logfile}.1"
|
/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
|
||||||
|
if [ -f /var/log/pihole.log.1 ]; then
|
||||||
|
echo " " > /var/log/pihole.log.1
|
||||||
|
chmod 644 /var/log/pihole.log.1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ "$*" != *"quiet"* ]]; then
|
# Delete most recent 24 hours from FTL's database, leave even older data intact (don't wipe out all history)
|
||||||
echo -e "${OVER} ${TICK} Flushed ${logfile} ..."
|
deleted=$(sqlite3 "${DBFILE}" "DELETE FROM queries WHERE timestamp >= strftime('%s','now')-86400; select changes() from queries limit 1")
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Manual flushing
|
# Restart pihole-FTL to force reloading history
|
||||||
flush_log "${LOGFILE}"
|
sudo pihole restartdns
|
||||||
flush_log "${FTLFILE}"
|
|
||||||
flush_log "${WEBFILE}"
|
|
||||||
|
|
||||||
if [[ "$*" != *"quiet"* ]]; then
|
|
||||||
echo -ne " ${INFO} Flushing database, DNS resolution temporarily unavailable ..."
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Stop FTL to make sure it doesn't write to the database while we're deleting data
|
if [[ "$@" != *"quiet"* ]]; then
|
||||||
service pihole-FTL stop
|
echo -e "${OVER} ${TICK} Flushed /var/log/pihole.log"
|
||||||
|
echo -e " ${TICK} Deleted ${deleted} queries from database"
|
||||||
# Delete most recent 24 hours from FTL's database, leave even older data intact (don't wipe out all history)
|
|
||||||
deleted=$(pihole-FTL sqlite3 -ni "${DBFILE}" "DELETE FROM query_storage WHERE timestamp >= strftime('%s','now')-86400; select changes() from query_storage limit 1")
|
|
||||||
|
|
||||||
# Restart FTL
|
|
||||||
service pihole-FTL restart
|
|
||||||
if [[ "$*" != *"quiet"* ]]; then
|
|
||||||
echo -e "${OVER} ${TICK} Deleted ${deleted} queries from long-term query database"
|
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Pi-hole: A black hole for Internet advertisements
|
|
||||||
# (c) 2025 Pi-hole, LLC (https://pi-hole.net)
|
|
||||||
# Network-wide ad blocking via your own hardware.
|
|
||||||
#
|
|
||||||
# Rotate Pi-hole's log file
|
|
||||||
#
|
|
||||||
# This file is copyright under the latest version of the EUPL.
|
|
||||||
# Please see LICENSE file for your rights under this license.
|
|
||||||
|
|
||||||
colfile="/opt/pihole/COL_TABLE"
|
|
||||||
# shellcheck source="./advanced/Scripts/COL_TABLE"
|
|
||||||
source ${colfile}
|
|
||||||
|
|
||||||
readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
|
||||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
|
||||||
# shellcheck source="./advanced/Scripts/utils.sh"
|
|
||||||
source "${utilsfile}"
|
|
||||||
|
|
||||||
# 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 log file location
|
|
||||||
LOGFILE=$(getFTLConfigValue "files.log.dnsmasq")
|
|
||||||
if [ -z "$LOGFILE" ]; then
|
|
||||||
LOGFILE="/var/log/pihole/pihole.log"
|
|
||||||
fi
|
|
||||||
FTLFILE=$(getFTLConfigValue "files.log.ftl")
|
|
||||||
if [ -z "$FTLFILE" ]; then
|
|
||||||
FTLFILE="/var/log/pihole/FTL.log"
|
|
||||||
fi
|
|
||||||
WEBFILE=$(getFTLConfigValue "files.log.webserver")
|
|
||||||
if [ -z "$WEBFILE" ]; then
|
|
||||||
WEBFILE="/var/log/pihole/webserver.log"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Helper function to handle log rotation for a single file
|
|
||||||
rotate_log() {
|
|
||||||
# This function copies x.log over to x.log.1
|
|
||||||
# and then empties x.log
|
|
||||||
# Note that moving the file is not an option, as
|
|
||||||
# dnsmasq would happily continue writing into the
|
|
||||||
# moved file (it will have the same file handler)
|
|
||||||
local logfile="$1"
|
|
||||||
if [[ "$*" != *"quiet"* ]]; then
|
|
||||||
echo -ne " ${INFO} Rotating ${logfile} ..."
|
|
||||||
fi
|
|
||||||
cp -p "${logfile}" "${logfile}.1"
|
|
||||||
echo " " > "${logfile}"
|
|
||||||
chmod 640 "${logfile}"
|
|
||||||
if [[ "$*" != *"quiet"* ]]; then
|
|
||||||
echo -e "${OVER} ${TICK} Rotated ${logfile} ..."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Nightly logrotation
|
|
||||||
if command -v /usr/sbin/logrotate >/dev/null; then
|
|
||||||
# Logrotate once
|
|
||||||
if [[ "$*" != *"quiet"* ]]; then
|
|
||||||
echo -ne " ${INFO} Running logrotate ..."
|
|
||||||
fi
|
|
||||||
mkdir -p "${STATEFILE%/*}"
|
|
||||||
/usr/sbin/logrotate --force --state "${STATEFILE}" /etc/pihole/logrotate
|
|
||||||
else
|
|
||||||
# Handle rotation for each log file
|
|
||||||
rotate_log "${LOGFILE}"
|
|
||||||
rotate_log "${FTLFILE}"
|
|
||||||
rotate_log "${WEBFILE}"
|
|
||||||
fi
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Pi-hole: A black hole for Internet advertisements
|
|
||||||
# (c) 2019 Pi-hole, LLC (https://pi-hole.net)
|
|
||||||
# Network-wide ad blocking via your own hardware.
|
|
||||||
#
|
|
||||||
# Network table flush
|
|
||||||
#
|
|
||||||
# This file is copyright under the latest version of the EUPL.
|
|
||||||
# Please see LICENSE file for your rights under this license.
|
|
||||||
|
|
||||||
coltable="/opt/pihole/COL_TABLE"
|
|
||||||
if [[ -f ${coltable} ]]; then
|
|
||||||
# shellcheck source="./advanced/Scripts/COL_TABLE"
|
|
||||||
source ${coltable}
|
|
||||||
fi
|
|
||||||
|
|
||||||
PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
|
||||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
|
||||||
# shellcheck source=./advanced/Scripts/utils.sh
|
|
||||||
source "${utilsfile}"
|
|
||||||
|
|
||||||
# Source api functions
|
|
||||||
# shellcheck source="./advanced/Scripts/api.sh"
|
|
||||||
. "${PI_HOLE_SCRIPT_DIR}/api.sh"
|
|
||||||
|
|
||||||
flushNetwork(){
|
|
||||||
local output
|
|
||||||
|
|
||||||
echo -ne " ${INFO} Flushing network table ..."
|
|
||||||
|
|
||||||
local data status error
|
|
||||||
# Authenticate with FTL
|
|
||||||
LoginAPI
|
|
||||||
|
|
||||||
# send query again
|
|
||||||
data=$(PostFTLData "action/flush/network" "" "status")
|
|
||||||
|
|
||||||
# Separate the status from the data
|
|
||||||
status=$(printf %s "${data#"${data%???}"}")
|
|
||||||
data=$(printf %s "${data%???}")
|
|
||||||
|
|
||||||
# If there is an .error object in the returned data, display it
|
|
||||||
local error
|
|
||||||
error=$(jq --compact-output <<< "${data}" '.error')
|
|
||||||
if [[ $error != "null" && $error != "" ]]; then
|
|
||||||
echo -e "${OVER} ${CROSS} Failed to flush the network table:"
|
|
||||||
echo -e " $(jq <<< "${data}" '.error')"
|
|
||||||
LogoutAPI
|
|
||||||
exit 1
|
|
||||||
elif [[ "${status}" == "200" ]]; then
|
|
||||||
echo -e "${OVER} ${TICK} Flushed network table"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Delete session
|
|
||||||
LogoutAPI
|
|
||||||
}
|
|
||||||
|
|
||||||
flushArp(){
|
|
||||||
# Flush ARP cache of the host
|
|
||||||
if ! output=$(ip -s -s neigh flush all 2>&1); then
|
|
||||||
echo -e "${OVER} ${CROSS} Failed to flush ARP cache"
|
|
||||||
echo " Output: ${output}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Process all options (if present)
|
|
||||||
while [ "$#" -gt 0 ]; do
|
|
||||||
case "$1" in
|
|
||||||
"--arp" ) doARP=true ;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
flushNetwork
|
|
||||||
|
|
||||||
if [[ "${doARP}" == true ]]; then
|
|
||||||
echo -ne " ${INFO} Flushing ARP cache"
|
|
||||||
if flushArp; then
|
|
||||||
echo -e "${OVER} ${TICK} Flushed ARP cache"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
@@ -1,144 +1,252 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC1090
|
||||||
# Pi-hole: A black hole for Internet advertisements
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
# (c) 2023 Pi-hole, LLC (https://pi-hole.net)
|
# (c) 2018 Pi-hole, LLC (https://pi-hole.net)
|
||||||
# Network-wide ad blocking via your own hardware.
|
# Network-wide ad blocking via your own hardware.
|
||||||
#
|
#
|
||||||
# Search Adlists
|
# Query Domain Lists
|
||||||
#
|
#
|
||||||
# This file is copyright under the latest version of the EUPL.
|
# This file is copyright under the latest version of the EUPL.
|
||||||
# Please see LICENSE file for your rights under this license.
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
# Globals
|
# Globals
|
||||||
PI_HOLE_INSTALL_DIR="/opt/pihole"
|
piholeDir="/etc/pihole"
|
||||||
max_results="20"
|
gravityDBfile="${piholeDir}/gravity.db"
|
||||||
partial="false"
|
options="$*"
|
||||||
domain=""
|
adlist=""
|
||||||
|
all=""
|
||||||
|
exact=""
|
||||||
|
blockpage=""
|
||||||
|
matchType="match"
|
||||||
|
|
||||||
# Source color table
|
|
||||||
colfile="/opt/pihole/COL_TABLE"
|
colfile="/opt/pihole/COL_TABLE"
|
||||||
# shellcheck source="./advanced/Scripts/COL_TABLE"
|
source "${colfile}"
|
||||||
. "${colfile}"
|
|
||||||
|
|
||||||
# Source api functions
|
# Scan an array of files for matching strings
|
||||||
# shellcheck source="./advanced/Scripts/api.sh"
|
scanList(){
|
||||||
. "${PI_HOLE_INSTALL_DIR}/api.sh"
|
# Escape full stops
|
||||||
|
local domain="${1}" esc_domain="${1//./\\.}" lists="${2}" type="${3:-}"
|
||||||
|
|
||||||
Help() {
|
# Prevent grep from printing file path
|
||||||
|
cd "$piholeDir" || exit 1
|
||||||
|
|
||||||
|
# Prevent grep -i matching slowly: http://bit.ly/2xFXtUX
|
||||||
|
export LC_CTYPE=C
|
||||||
|
|
||||||
|
# /dev/null forces filename to be printed when only one list has been generated
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
case "${type}" in
|
||||||
|
"exact" ) grep -i -E -l "(^|(?<!#)\\s)${esc_domain}($|\\s|#)" ${lists} /dev/null 2>/dev/null;;
|
||||||
|
# Create array of regexps
|
||||||
|
# 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" ) awk 'NR==FNR{regexps[$0];next}{for (r in regexps)if($0 ~ r)print r}' \
|
||||||
|
<(echo "${lists}") <(echo "${domain}") 2>/dev/null;;
|
||||||
|
* ) grep -i "${esc_domain}" ${lists} /dev/null 2>/dev/null;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${options}" == "-h" ]] || [[ "${options}" == "--help" ]]; then
|
||||||
echo "Usage: pihole -q [option] <domain>
|
echo "Usage: pihole -q [option] <domain>
|
||||||
Example: 'pihole -q --partial domain.com'
|
Example: 'pihole -q -exact domain.com'
|
||||||
Query the adlists for a specified domain
|
Query the adlists for a specified domain
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--partial Search the adlists for partially matching domains
|
-adlist Print the name of the block list URL
|
||||||
--all Return all query matches within the adlists
|
-exact Search the block lists for exact domain matches
|
||||||
-h, --help Show this help dialog"
|
-all Return all query matches within a block list
|
||||||
exit 0
|
-h, --help Show this help dialog"
|
||||||
}
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
GenerateOutput() {
|
# Handle valid options
|
||||||
local counts data num_gravity num_lists search_type_str
|
if [[ "${options}" == *"-bp"* ]]; then
|
||||||
local gravity_data_csv lists_data_csv line url type color
|
exact="exact"; blockpage=true
|
||||||
data="${1}"
|
else
|
||||||
|
[[ "${options}" == *"-adlist"* ]] && adlist=true
|
||||||
# Get count of list and gravity matches
|
[[ "${options}" == *"-all"* ]] && all=true
|
||||||
# Use JQ to count number of entries in lists and gravity
|
if [[ "${options}" == *"-exact"* ]]; then
|
||||||
# (output is number of list matches then number of gravity matches)
|
exact="exact"; matchType="exact ${matchType}"
|
||||||
counts=$(printf %s "${data}" | jq --raw-output '(.search.domains | length), (.search.gravity | group_by(.address,.type) | length)')
|
|
||||||
num_lists=$(echo "$counts" | sed -n '1p')
|
|
||||||
num_gravity=$(echo "$counts" | sed -n '2p')
|
|
||||||
|
|
||||||
if [ "${partial}" = true ]; then
|
|
||||||
search_type_str="partially"
|
|
||||||
else
|
|
||||||
search_type_str="exactly"
|
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Results from allow/deny list
|
# Strip valid options, leaving only the domain and invalid options
|
||||||
printf "%s\n\n" "Found ${num_lists} domains ${search_type_str} matching '${COL_BLUE}${domain}${COL_NC}'."
|
# This allows users to place the options before or after the domain
|
||||||
if [ "${num_lists}" -gt 0 ]; then
|
options=$(sed -E 's/ ?-(bp|adlists?|all|exact) ?//g' <<< "${options}")
|
||||||
# Convert the data to a csv, each line is a "domain,type" string
|
|
||||||
# not using jq's @csv here as it quotes each value individually
|
|
||||||
lists_data_csv=$(printf %s "${data}" | jq --raw-output '.search.domains | map([.domain, .type] | join(",")) | join("\n")')
|
|
||||||
|
|
||||||
# Generate output for each csv line, separating line in a domain and type substring at the ','
|
# Handle remaining options
|
||||||
echo "${lists_data_csv}" | while read -r line; do
|
# If $options contain non ASCII characters, convert to punycode
|
||||||
printf "%s\n\n" " - ${COL_GREEN}${line%,*}${COL_NC} (type: exact ${line#*,} domain)"
|
case "${options}" in
|
||||||
done
|
"" ) str="No domain specified";;
|
||||||
fi
|
*" "* ) str="Unknown query option specified";;
|
||||||
|
*[![:ascii:]]* ) domainQuery=$(idn2 "${options}");;
|
||||||
|
* ) domainQuery="${options}";;
|
||||||
|
esac
|
||||||
|
|
||||||
# Results from gravity
|
if [[ -n "${str:-}" ]]; then
|
||||||
printf "%s\n\n" "Found ${num_gravity} lists ${search_type_str} matching '${COL_BLUE}${domain}${COL_NC}'."
|
echo -e "${str}${COL_NC}\\nTry 'pihole -q --help' for more information."
|
||||||
if [ "${num_gravity}" -gt 0 ]; then
|
exit 1
|
||||||
# Convert the data to a csv, each line is a "URL,type,domain,domain,...." string
|
fi
|
||||||
# not using jq's @csv here as it quotes each value individually
|
|
||||||
gravity_data_csv=$(printf %s "${data}" | jq --raw-output '.search.gravity | group_by(.address,.type) | map([.[0].address, .[0].type, (.[] | .domain)] | join(",")) | join("\n")')
|
|
||||||
|
|
||||||
# Generate line-by-line output for each csv line
|
scanDatabaseTable() {
|
||||||
echo "${gravity_data_csv}" | while read -r line; do
|
local domain table type querystr result
|
||||||
# Get first part of the line, the URL
|
domain="$(printf "%q" "${1}")"
|
||||||
url=${line%%,*}
|
table="${2}"
|
||||||
|
type="${3:-}"
|
||||||
|
|
||||||
# cut off URL, leaving "type,domain,domain,...."
|
# As underscores are legitimate parts of domains, we escape them when using the LIKE operator.
|
||||||
line=${line#*,}
|
# Underscores are SQLite wildcards matching exactly one character. We obviously want to suppress this
|
||||||
type=${line%%,*}
|
# behavior. The "ESCAPE '\'" clause specifies that an underscore preceded by an '\' should be matched
|
||||||
# type == "block" -> red, type == "allow" -> green
|
# as a literal underscore character. We pretreat the $domain variable accordingly to escape underscores.
|
||||||
if [ "${type}" = "block" ]; then
|
case "${type}" in
|
||||||
color="${COL_RED}"
|
"exact" ) querystr="SELECT domain FROM vw_${table} WHERE domain = '${domain}'";;
|
||||||
else
|
* ) querystr="SELECT domain FROM vw_${table} WHERE domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
|
||||||
color="${COL_GREEN}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# print adlist URL
|
|
||||||
printf "%s (%s)\n\n" " - ${COL_BLUE}${url}${COL_NC}" "${color}${type}${COL_NC}"
|
|
||||||
|
|
||||||
# cut off type, leaving "domain,domain,...."
|
|
||||||
line=${line#*,}
|
|
||||||
# Replace commas with newlines and format output
|
|
||||||
echo "${line}" | sed 's/,/\n/g' | sed "s/^/ - ${COL_GREEN}/" | sed "s/$/${COL_NC}/"
|
|
||||||
printf "\n\n"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If no exact results were found, suggest using partial matching
|
|
||||||
if [ "${num_lists}" -eq 0 ] && [ "${num_gravity}" -eq 0 ] && [ "${partial}" = false ]; then
|
|
||||||
printf "%s\n" "Hint: Try partial matching with"
|
|
||||||
printf "%s\n\n" " ${COL_GREEN}pihole -q --partial ${domain}${COL_NC}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
Main() {
|
|
||||||
local data
|
|
||||||
|
|
||||||
if [ -z "${domain}" ]; then
|
|
||||||
echo "No domain specified"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# domains are lowercased and converted to punycode by FTL since
|
|
||||||
# https://github.com/pi-hole/FTL/pull/1715
|
|
||||||
# no need to do it here
|
|
||||||
|
|
||||||
# Authenticate with FTL
|
|
||||||
LoginAPI
|
|
||||||
|
|
||||||
# send query again
|
|
||||||
data=$(GetFTLData "search/${domain}?N=${max_results}&partial=${partial}")
|
|
||||||
|
|
||||||
GenerateOutput "${data}"
|
|
||||||
|
|
||||||
# Delete session
|
|
||||||
LogoutAPI
|
|
||||||
}
|
|
||||||
|
|
||||||
# Process all options (if present)
|
|
||||||
while [ "$#" -gt 0 ]; do
|
|
||||||
case "$1" in
|
|
||||||
"-h" | "--help") Help ;;
|
|
||||||
"--partial") partial="true" ;;
|
|
||||||
"--all") max_results=10000 ;; # hard-coded FTL limit
|
|
||||||
*) domain=$1 ;;
|
|
||||||
esac
|
esac
|
||||||
shift
|
|
||||||
|
# Send prepared query to gravity database
|
||||||
|
result="$(sqlite3 "${gravityDBfile}" "${querystr}")" 2> /dev/null
|
||||||
|
if [[ -z "${result}" ]]; then
|
||||||
|
# Return early when there are no matches in this table
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mark domain as having been white-/blacklist matched (global variable)
|
||||||
|
wbMatch=true
|
||||||
|
|
||||||
|
# Print table name
|
||||||
|
if [[ -z "${blockpage}" ]]; then
|
||||||
|
echo " ${matchType^} found in ${COL_BOLD}${table^}${COL_NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Loop over results and print them
|
||||||
|
mapfile -t results <<< "${result}"
|
||||||
|
for result in "${results[@]}"; do
|
||||||
|
if [[ -n "${blockpage}" ]]; then
|
||||||
|
echo "π ${result}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo " ${result}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Scan Whitelist and Blacklist
|
||||||
|
scanDatabaseTable "${domainQuery}" "whitelist" "${exact}"
|
||||||
|
scanDatabaseTable "${domainQuery}" "blacklist" "${exact}"
|
||||||
|
|
||||||
|
# Scan Regex table
|
||||||
|
mapfile -t regexList < <(sqlite3 "${gravityDBfile}" "SELECT domain FROM vw_regex" 2> /dev/null)
|
||||||
|
|
||||||
|
# If we have regexps to process
|
||||||
|
if [[ "${#regexList[@]}" -ne 0 ]]; then
|
||||||
|
# Split regexps over a new line
|
||||||
|
str_regexList=$(printf '%s\n' "${regexList[@]}")
|
||||||
|
# Check domainQuery against regexps
|
||||||
|
mapfile -t regexMatches < <(scanList "${domainQuery}" "${str_regexList}" "regex")
|
||||||
|
# If there were regex matches
|
||||||
|
if [[ "${#regexMatches[@]}" -ne 0 ]]; then
|
||||||
|
# Split matching regexps over a new line
|
||||||
|
str_regexMatches=$(printf '%s\n' "${regexMatches[@]}")
|
||||||
|
# Form a "matched" message
|
||||||
|
str_message="${matchType^} found in ${COL_BOLD}Regex list${COL_NC}"
|
||||||
|
# Form a "results" message
|
||||||
|
str_result="${COL_BOLD}${str_regexMatches}${COL_NC}"
|
||||||
|
# If we are displaying more than just the source of the block
|
||||||
|
if [[ -z "${blockpage}" ]]; then
|
||||||
|
# Set the wildcard match flag
|
||||||
|
wcMatch=true
|
||||||
|
# Echo the "matched" message, indented by one space
|
||||||
|
echo " ${str_message}"
|
||||||
|
# Echo the "results" message, each line indented by three spaces
|
||||||
|
# shellcheck disable=SC2001
|
||||||
|
echo "${str_result}" | sed 's/^/ /'
|
||||||
|
else
|
||||||
|
echo "π .wildcard"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get version sorted *.domains filenames (without dir path)
|
||||||
|
lists=("$(cd "$piholeDir" || exit 0; printf "%s\\n" -- *.domains | sort -V)")
|
||||||
|
|
||||||
|
# Query blocklists for occurences of domain
|
||||||
|
mapfile -t results <<< "$(scanList "${domainQuery}" "${lists[*]}" "${exact}")"
|
||||||
|
|
||||||
|
# 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 block lists"
|
||||||
|
exit 0
|
||||||
|
elif [[ -z "${results[*]}" ]]; then
|
||||||
|
# Result found in WL/BL/Wildcards
|
||||||
|
exit 0
|
||||||
|
elif [[ -z "${all}" ]] && [[ "${#results[*]}" -ge 100 ]]; then
|
||||||
|
echo -e " ${INFO} Over 100 ${exact/t/t }results found for ${COL_BOLD}${domainQuery}${COL_NC}
|
||||||
|
This can be overridden using the -all option"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove unwanted content from non-exact $results
|
||||||
|
if [[ -z "${exact}" ]]; then
|
||||||
|
# Delete lines starting with #
|
||||||
|
# Remove comments after domain
|
||||||
|
# Remove hosts format IP address
|
||||||
|
mapfile -t results <<< "$(IFS=$'\n'; sed \
|
||||||
|
-e "/:#/d" \
|
||||||
|
-e "s/[ \\t]#.*//g" \
|
||||||
|
-e "s/:.*[ \\t]/:/g" \
|
||||||
|
<<< "${results[*]}")"
|
||||||
|
# Exit if result was in a comment
|
||||||
|
[[ -z "${results[*]}" ]] && exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get adlist file content as array
|
||||||
|
if [[ -n "${adlist}" ]] || [[ -n "${blockpage}" ]]; then
|
||||||
|
# Retrieve source URLs from gravity database
|
||||||
|
mapfile -t adlists <<< "$(sqlite3 "${gravityDBfile}" "SELECT address FROM vw_adlist;" 2> /dev/null)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Print "Exact matches for" title
|
||||||
|
if [[ -n "${exact}" ]] && [[ -z "${blockpage}" ]]; then
|
||||||
|
plural=""; [[ "${#results[*]}" -gt 1 ]] && plural="es"
|
||||||
|
echo " ${matchType^}${plural} for ${COL_BOLD}${domainQuery}${COL_NC} found in:"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for result in "${results[@]}"; do
|
||||||
|
fileName="${result/:*/}"
|
||||||
|
|
||||||
|
# Determine *.domains URL using filename's number
|
||||||
|
if [[ -n "${adlist}" ]] || [[ -n "${blockpage}" ]]; then
|
||||||
|
fileNum="${fileName/list./}"; fileNum="${fileNum%%.*}"
|
||||||
|
fileName="${adlists[$fileNum]}"
|
||||||
|
|
||||||
|
# Discrepency occurs when adlists has been modified, but Gravity has not been run
|
||||||
|
if [[ -z "${fileName}" ]]; then
|
||||||
|
fileName="${COL_LIGHT_RED}(no associated adlists URL found)${COL_NC}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${blockpage}" ]]; then
|
||||||
|
echo "${fileNum} ${fileName}"
|
||||||
|
elif [[ -n "${exact}" ]]; then
|
||||||
|
echo " ${fileName}"
|
||||||
|
else
|
||||||
|
if [[ ! "${fileName}" == "${fileName_prev:-}" ]]; then
|
||||||
|
count=""
|
||||||
|
echo " ${matchType^} found in ${COL_BOLD}${fileName}${COL_NC}:"
|
||||||
|
fileName_prev="${fileName}"
|
||||||
|
fi
|
||||||
|
: $((count++))
|
||||||
|
|
||||||
|
# Print matching domain if $max_count has not been reached
|
||||||
|
[[ -z "${all}" ]] && max_count="50"
|
||||||
|
if [[ -z "${all}" ]] && [[ "${count}" -ge "${max_count}" ]]; then
|
||||||
|
[[ "${count}" -gt "${max_count}" ]] && continue
|
||||||
|
echo " ${COL_GRAY}Over ${count} results found, skipping rest of file${COL_NC}"
|
||||||
|
else
|
||||||
|
echo " ${result#*:}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
Main "${domain}"
|
exit 0
|
||||||
|
|||||||
74
advanced/Scripts/setupLCD.sh
Executable file
74
advanced/Scripts/setupLCD.sh
Executable file
@@ -0,0 +1,74 @@
|
|||||||
|
#!/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.
|
||||||
|
#
|
||||||
|
# Automatically configures the Pi to use the 2.8 LCD screen to display stats on it (also works over ssh)
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
############ FUNCTIONS ###########
|
||||||
|
|
||||||
|
# Borrowed from adafruit-pitft-helper < borrowed from raspi-config
|
||||||
|
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L324-L334
|
||||||
|
getInitSys() {
|
||||||
|
if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then
|
||||||
|
SYSTEMD=1
|
||||||
|
elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then
|
||||||
|
SYSTEMD=0
|
||||||
|
else
|
||||||
|
echo "Unrecognised init system"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Borrowed from adafruit-pitft-helper:
|
||||||
|
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L274-L285
|
||||||
|
autoLoginPiToConsole() {
|
||||||
|
if [ -e /etc/init.d/lightdm ]; then
|
||||||
|
if [ ${SYSTEMD} -eq 1 ]; then
|
||||||
|
systemctl set-default multi-user.target
|
||||||
|
ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
|
||||||
|
else
|
||||||
|
update-rc.d lightdm disable 2
|
||||||
|
sed /etc/inittab -i -e "s/1:2345:respawn:\/sbin\/getty --noclear 38400 tty1/1:2345:respawn:\/bin\/login -f pi tty1 <\/dev\/tty1 >\/dev\/tty1 2>&1/"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
######### SCRIPT ###########
|
||||||
|
# Set pi to log in automatically
|
||||||
|
getInitSys
|
||||||
|
autoLoginPiToConsole
|
||||||
|
|
||||||
|
# Set chronomter to run automatically when pi logs in
|
||||||
|
echo /usr/local/bin/chronometer.sh >> /home/pi/.bashrc
|
||||||
|
# OR
|
||||||
|
#$SUDO echo /usr/local/bin/chronometer.sh >> /etc/profile
|
||||||
|
|
||||||
|
# Set up the LCD screen based on Adafruits instuctions:
|
||||||
|
# https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/easy-install
|
||||||
|
curl -SLs https://apt.adafruit.com/add-pin | bash
|
||||||
|
apt-get -y install raspberrypi-bootloader
|
||||||
|
apt-get -y install adafruit-pitft-helper
|
||||||
|
adafruit-pitft-helper -t 28r
|
||||||
|
|
||||||
|
# Download the cmdline.txt file that prevents the screen from going blank after a period of time
|
||||||
|
mv /boot/cmdline.txt /boot/cmdline.orig
|
||||||
|
curl -o /boot/cmdline.txt https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/cmdline.txt
|
||||||
|
|
||||||
|
# Back up the original file and download the new one
|
||||||
|
mv /etc/default/console-setup /etc/default/console-setup.orig
|
||||||
|
curl -o /etc/default/console-setup https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/console-setup
|
||||||
|
|
||||||
|
# Instantly apply the font change to the LCD screen
|
||||||
|
setupcon
|
||||||
|
|
||||||
|
reboot
|
||||||
|
|
||||||
|
# Start showing the stats on the screen by running the command on another tty:
|
||||||
|
# http://unix.stackexchange.com/questions/170063/start-a-process-on-a-different-tty
|
||||||
|
#setsid sh -c 'exec /usr/local/bin/chronometer.sh <> /dev/tty1 >&0 2>&1'
|
||||||
@@ -11,85 +11,66 @@
|
|||||||
# Please see LICENSE file for your rights under this license.
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
# Variables
|
# Variables
|
||||||
readonly ADMIN_INTERFACE_GIT_URL="https://github.com/pi-hole/web.git"
|
readonly ADMIN_INTERFACE_GIT_URL="https://github.com/pi-hole/AdminLTE.git"
|
||||||
|
readonly ADMIN_INTERFACE_DIR="/var/www/html/admin"
|
||||||
readonly PI_HOLE_GIT_URL="https://github.com/pi-hole/pi-hole.git"
|
readonly PI_HOLE_GIT_URL="https://github.com/pi-hole/pi-hole.git"
|
||||||
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||||
|
|
||||||
SKIP_INSTALL=true
|
# shellcheck disable=SC2034
|
||||||
|
PH_TEST=true
|
||||||
|
|
||||||
# when --check-only is passed to this script, it will not perform the actual update
|
# when --check-only is passed to this script, it will not perform the actual update
|
||||||
CHECK_ONLY=false
|
CHECK_ONLY=false
|
||||||
|
|
||||||
# shellcheck source="./automated install/basic-install.sh"
|
# shellcheck disable=SC1090
|
||||||
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||||
# shellcheck source=./advanced/Scripts/COL_TABLE
|
# shellcheck disable=SC1091
|
||||||
source "/opt/pihole/COL_TABLE"
|
source "/opt/pihole/COL_TABLE"
|
||||||
# shellcheck source="./advanced/Scripts/utils.sh"
|
|
||||||
source "${PI_HOLE_INSTALL_DIR}/utils.sh"
|
|
||||||
|
|
||||||
# is_repo() sourced from basic-install.sh
|
# is_repo() sourced from basic-install.sh
|
||||||
# make_repo() sourced from basic-install.sh
|
# make_repo() sourced from basic-install.sh
|
||||||
# update_repo() source from basic-install.sh
|
# update_repo() source from basic-install.sh
|
||||||
# getGitFiles() sourced from basic-install.sh
|
# getGitFiles() sourced from basic-install.sh
|
||||||
|
# get_binary_name() sourced from basic-install.sh
|
||||||
# FTLcheckUpdate() sourced from basic-install.sh
|
# FTLcheckUpdate() sourced from basic-install.sh
|
||||||
# getFTLConfigValue() sourced from utils.sh
|
|
||||||
|
|
||||||
# Honour configured paths for the web application.
|
|
||||||
ADMIN_INTERFACE_DIR=$(getFTLConfigValue "webserver.paths.webroot")$(getFTLConfigValue "webserver.paths.webhome")
|
|
||||||
readonly ADMIN_INTERFACE_DIR
|
|
||||||
|
|
||||||
GitCheckUpdateAvail() {
|
GitCheckUpdateAvail() {
|
||||||
local directory
|
local directory
|
||||||
local curBranch
|
|
||||||
directory="${1}"
|
directory="${1}"
|
||||||
curdir=$PWD
|
curdir=$PWD
|
||||||
cd "${directory}" || exit 1
|
cd "${directory}" || return
|
||||||
|
|
||||||
# Fetch latest changes in this repo
|
# Fetch latest changes in this repo
|
||||||
if ! git fetch --quiet origin ; then
|
git fetch --quiet origin
|
||||||
echo -e "\\n ${COL_RED}Error: Unable to update local repository. Contact Pi-hole Support.${COL_NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check current branch. If it is master, then check for the latest available tag instead of latest commit.
|
# @ alone is a shortcut for HEAD. Older versions of git
|
||||||
curBranch=$(git rev-parse --abbrev-ref HEAD)
|
# need @{0}
|
||||||
if [[ "${curBranch}" == "master" ]]; then
|
LOCAL="$(git rev-parse "@{0}")"
|
||||||
# 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
|
|
||||||
|
|
||||||
|
# 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
|
if [[ "${#LOCAL}" == 0 ]]; then
|
||||||
echo -e "\\n ${COL_RED}Error: Local revision could not be obtained, please contact Pi-hole Support"
|
echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support"
|
||||||
echo -e " Additional debugging output:${COL_NC}"
|
echo -e " Additional debugging output:${COL_NC}"
|
||||||
git status
|
git status
|
||||||
exit 1
|
exit
|
||||||
fi
|
fi
|
||||||
if [[ "${#REMOTE}" == 0 ]]; then
|
if [[ "${#REMOTE}" == 0 ]]; then
|
||||||
echo -e "\\n ${COL_RED}Error: Remote revision could not be obtained, please contact Pi-hole Support"
|
echo -e "\\n ${COL_LIGHT_RED}Error: Remote revision could not be obtained, please contact Pi-hole Support"
|
||||||
echo -e " Additional debugging output:${COL_NC}"
|
echo -e " Additional debugging output:${COL_NC}"
|
||||||
git status
|
git status
|
||||||
exit 1
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Change back to original directory
|
# Change back to original directory
|
||||||
cd "${curdir}" || exit 1
|
cd "${curdir}" || exit
|
||||||
|
|
||||||
if [[ "${LOCAL}" != "${REMOTE}" ]]; then
|
if [[ "${LOCAL}" != "${REMOTE}" ]]; then
|
||||||
# Local branch is behind remote branch -> Update
|
# Local branch is behind remote branch -> Update
|
||||||
@@ -102,52 +83,8 @@ GitCheckUpdateAvail() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
updateWarnDialog() {
|
|
||||||
# Display the warning dialog
|
|
||||||
|
|
||||||
local core_str web_str ftl_str
|
|
||||||
|
|
||||||
if [[ "${core_update}" == true ]]; then
|
|
||||||
core_str="Core: \\Zb\\Z1update available\\Zn"
|
|
||||||
else
|
|
||||||
core_str="Core: \\Zb\\Z4up to date\\Zn"
|
|
||||||
fi
|
|
||||||
if [[ "${web_update}" == true ]]; then
|
|
||||||
web_str="Web: \\Zb\\Z1update available\\Zn"
|
|
||||||
else
|
|
||||||
web_str="Web: \\Zb\\Z4up to date\\Zn"
|
|
||||||
fi
|
|
||||||
if [[ "${FTL_update}" == true ]]; then
|
|
||||||
ftl_str="FTL: \\Zb\\Z1update available\\Zn"
|
|
||||||
else
|
|
||||||
ftl_str="FTL: \\Zb\\Z4up to date\\Zn"
|
|
||||||
fi
|
|
||||||
# shellcheck disable=SC2154 # Variables "${r}" "${c}" are defined in the main script
|
|
||||||
dialog --no-shadow --clear --keep-tite \
|
|
||||||
--colors \
|
|
||||||
--backtitle "Updating Pi-hole" \
|
|
||||||
--title "Warning" \
|
|
||||||
--no-button "Exit" --yes-button "Continue" \
|
|
||||||
--defaultno \
|
|
||||||
--yesno "\\nThe following Pi-hole components are going to be updated.\\n\\n\\n\
|
|
||||||
$core_str\\n\
|
|
||||||
$web_str\\n\
|
|
||||||
$ftl_str\\n\\n\\n\
|
|
||||||
\\Zb\\Z1IMPORTANT:\\Zn Make a (teleporter) backup of your system!\\n\\n\
|
|
||||||
Updates can come with significant changes. Please read the changelog at https://pi-hole.net/blog carefully.\\n\\n\\n\
|
|
||||||
Please confirm you want to start the update process." \
|
|
||||||
"${r}" "${c}" && result=0 || result="$?"
|
|
||||||
|
|
||||||
case "${result}" in
|
|
||||||
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
|
|
||||||
printf " %b User canceled the update process.\\n" "${INFO}"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
local basicError="\\n ${COL_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
|
local basicError="\\n ${COL_LIGHT_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
|
||||||
local core_update
|
local core_update
|
||||||
local web_update
|
local web_update
|
||||||
local FTL_update
|
local FTL_update
|
||||||
@@ -156,15 +93,12 @@ main() {
|
|||||||
web_update=false
|
web_update=false
|
||||||
FTL_update=false
|
FTL_update=false
|
||||||
|
|
||||||
|
# shellcheck disable=1090,2154
|
||||||
# Install packages used by this installation script (necessary if users have removed e.g. git from their systems)
|
source "${setupVars}"
|
||||||
package_manager_detect
|
|
||||||
build_dependency_package
|
|
||||||
install_dependent_packages
|
|
||||||
|
|
||||||
# This is unlikely
|
# This is unlikely
|
||||||
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||||
echo -e "\\n ${COL_RED}Error: Core Pi-hole repo is missing from system!"
|
echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!"
|
||||||
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
|
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
@@ -176,54 +110,39 @@ main() {
|
|||||||
echo -e " ${INFO} Pi-hole Core:\\t${COL_YELLOW}update available${COL_NC}"
|
echo -e " ${INFO} Pi-hole Core:\\t${COL_YELLOW}update available${COL_NC}"
|
||||||
else
|
else
|
||||||
core_update=false
|
core_update=false
|
||||||
echo -e " ${INFO} Pi-hole Core:\\t${COL_GREEN}up to date${COL_NC}"
|
echo -e " ${INFO} Pi-hole Core:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
echo -e "\\n ${COL_RED}Error: Web Admin repo is missing from system!"
|
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
|
||||||
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
|
echo -e "\\n ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!"
|
||||||
exit 1;
|
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
|
||||||
fi
|
exit 1;
|
||||||
|
|
||||||
if GitCheckUpdateAvail "${ADMIN_INTERFACE_DIR}" ; then
|
|
||||||
web_update=true
|
|
||||||
echo -e " ${INFO} Web Interface:\\t${COL_YELLOW}update available${COL_NC}"
|
|
||||||
else
|
|
||||||
web_update=false
|
|
||||||
echo -e " ${INFO} Web Interface:\\t${COL_GREEN}up to date${COL_NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Allow the user to skip this check if they are using a self-compiled FTL binary from an unsupported architecture
|
|
||||||
if [ "${skipFTL}" != true ]; then
|
|
||||||
local funcOutput
|
|
||||||
funcOutput=$(get_binary_name) #Store output of get_binary_name here
|
|
||||||
local binary
|
|
||||||
binary="pihole-FTL${funcOutput##*pihole-FTL}" #binary name will be the last line of the output of get_binary_name (it always begins with pihole-FTL)
|
|
||||||
|
|
||||||
if FTLcheckUpdate "${binary}" &>/dev/null; then
|
|
||||||
FTL_update=true
|
|
||||||
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
|
|
||||||
else
|
|
||||||
case $? in
|
|
||||||
1)
|
|
||||||
echo -e " ${INFO} FTL:\\t\\t${COL_GREEN}up to date${COL_NC}"
|
|
||||||
;;
|
|
||||||
2)
|
|
||||||
echo -e " ${INFO} FTL:\\t\\t${COL_RED}Branch is not available.${COL_NC}\\n\\t\\t\\tUse ${COL_GREEN}pihole checkout ftl [branchname]${COL_NC} to switch to a valid branch."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
3)
|
|
||||||
echo -e " ${INFO} FTL:\\t\\t${COL_RED}Something has gone wrong, cannot reach download server${COL_NC}"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo -e " ${INFO} FTL:\\t\\t${COL_RED}Something has gone wrong, contact support${COL_NC}"
|
|
||||||
exit 1
|
|
||||||
esac
|
|
||||||
FTL_update=false
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if GitCheckUpdateAvail "${ADMIN_INTERFACE_DIR}" ; then
|
||||||
|
web_update=true
|
||||||
|
echo -e " ${INFO} Web Interface:\\t${COL_YELLOW}update available${COL_NC}"
|
||||||
|
else
|
||||||
|
web_update=false
|
||||||
|
echo -e " ${INFO} Web Interface:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if FTLcheckUpdate > /dev/null; then
|
||||||
|
FTL_update=true
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
|
||||||
else
|
else
|
||||||
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}--skipFTL set - update check skipped${COL_NC}"
|
case $? in
|
||||||
|
1)
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Branch is not available.${COL_NC}\\n\\t\\t\\tUse ${COL_LIGHT_GREEN}pihole checkout ftl [branchname]${COL_NC} to switch to a valid branch."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Something has gone wrong, contact support${COL_NC}"
|
||||||
|
esac
|
||||||
FTL_update=false
|
FTL_update=false
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -238,7 +157,7 @@ main() {
|
|||||||
if [[ ! "${ftlBranch}" == "master" && ! "${ftlBranch}" == "development" ]]; then
|
if [[ ! "${ftlBranch}" == "master" && ! "${ftlBranch}" == "development" ]]; then
|
||||||
# Notify user that they are on a custom branch which might mean they they are lost
|
# Notify user that they are on a custom branch which might mean they they are lost
|
||||||
# behind if a branch was merged to development and got abandoned
|
# behind if a branch was merged to development and got abandoned
|
||||||
printf " %b %bWarning:%b You are using FTL from a custom branch (%s) and might be missing future releases.\\n" "${INFO}" "${COL_RED}" "${COL_NC}" "${ftlBranch}"
|
printf " %b %bWarning:%b You are using FTL from a custom branch (%s) and might be missing future releases.\\n" "${INFO}" "${COL_LIGHT_RED}" "${COL_NC}" "${ftlBranch}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${core_update}" == false && "${web_update}" == false && "${FTL_update}" == false ]]; then
|
if [[ "${core_update}" == false && "${web_update}" == false && "${FTL_update}" == false ]]; then
|
||||||
@@ -252,11 +171,6 @@ main() {
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# if there is any update, show the warning dialog and ask for confirmation
|
|
||||||
if [[ "${core_update}" == true || "${web_update}" == true || "${FTL_update}" == true ]]; then
|
|
||||||
updateWarnDialog
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${core_update}" == true ]]; then
|
if [[ "${core_update}" == true ]]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${INFO} Pi-hole core files out of date, updating local repo."
|
echo -e " ${INFO} Pi-hole core files out of date, updating local repo."
|
||||||
@@ -268,7 +182,7 @@ main() {
|
|||||||
echo ""
|
echo ""
|
||||||
echo -e " ${INFO} Pi-hole Web Admin files out of date, updating local repo."
|
echo -e " ${INFO} Pi-hole Web Admin files out of date, updating local repo."
|
||||||
getGitFiles "${ADMIN_INTERFACE_DIR}" "${ADMIN_INTERFACE_GIT_URL}"
|
getGitFiles "${ADMIN_INTERFACE_DIR}" "${ADMIN_INTERFACE_GIT_URL}"
|
||||||
echo -e " ${INFO} If you had made any changes in '${ADMIN_INTERFACE_DIR}', they have been stashed using 'git stash'"
|
echo -e " ${INFO} If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${FTL_update}" == true ]]; then
|
if [[ "${FTL_update}" == true ]]; then
|
||||||
@@ -277,42 +191,15 @@ main() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then
|
if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then
|
||||||
local addionalFlag
|
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
|
||||||
|
echo -e "${basicError}" && exit 1
|
||||||
if [[ ${skipFTL} == true ]]; then
|
|
||||||
addionalFlag="--skipFTL"
|
|
||||||
else
|
|
||||||
addionalFlag=""
|
|
||||||
fi
|
|
||||||
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --repair --unattended ${addionalFlag} || \
|
|
||||||
echo -e "${basicError}" && exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${FTL_update}" == true || "${core_update}" == true || "${web_update}" == true ]]; then
|
|
||||||
# Update local and remote versions via updatechecker
|
|
||||||
/opt/pihole/updatecheck.sh
|
|
||||||
echo -e " ${INFO} Local version file information updated."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# if there was only a web update, show the new versions
|
|
||||||
# (on core and FTL updates, this is done as part of the installer run)
|
|
||||||
if [[ "${web_update}" == true && "${FTL_update}" == false && "${core_update}" == false ]]; then
|
|
||||||
"${PI_HOLE_BIN_DIR}"/pihole version
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK_ONLY=false
|
if [[ "$1" == "--check-only" ]]; then
|
||||||
skipFTL=false
|
CHECK_ONLY=true
|
||||||
|
fi
|
||||||
# Check arguments
|
|
||||||
for var in "$@"; do
|
|
||||||
case "$var" in
|
|
||||||
"--check-only") CHECK_ONLY=true ;;
|
|
||||||
"--skipFTL") skipFTL=true ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
main
|
main
|
||||||
|
|||||||
@@ -8,130 +8,87 @@
|
|||||||
# This file is copyright under the latest version of the EUPL.
|
# This file is copyright under the latest version of the EUPL.
|
||||||
# Please see LICENSE file for your rights under this license.
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
# Credit: https://stackoverflow.com/a/46324904
|
||||||
|
function json_extract() {
|
||||||
|
local key=$1
|
||||||
|
local json=$2
|
||||||
|
|
||||||
|
local string_regex='"([^"\]|\\.)*"'
|
||||||
|
local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
|
||||||
|
local value_regex="${string_regex}|${number_regex}|true|false|null"
|
||||||
|
local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"
|
||||||
|
|
||||||
|
if [[ ${json} =~ ${pair_regex} ]]; then
|
||||||
|
echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
function get_local_branch() {
|
function get_local_branch() {
|
||||||
# Return active branch
|
# Return active branch
|
||||||
cd "${1}" 2>/dev/null || { echo "null"; return; }
|
cd "${1}" 2> /dev/null || return 1
|
||||||
git rev-parse --abbrev-ref HEAD || echo "null"
|
git rev-parse --abbrev-ref HEAD || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_local_version() {
|
function get_local_version() {
|
||||||
# Return active version
|
# Return active branch
|
||||||
cd "${1}" 2>/dev/null || { echo "null"; return; }
|
cd "${1}" 2> /dev/null || return 1
|
||||||
git describe --tags --always 2>/dev/null || echo "null"
|
git describe --long --dirty --tags 2> /dev/null || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_local_hash() {
|
# Source the setupvars config file
|
||||||
cd "${1}" 2>/dev/null || { echo "null"; return; }
|
# shellcheck disable=SC1091
|
||||||
git rev-parse --short=8 HEAD || echo "null"
|
. /etc/pihole/setupVars.conf
|
||||||
}
|
|
||||||
|
|
||||||
function get_remote_version() {
|
if [[ "$2" == "remote" ]]; then
|
||||||
# if ${2} is = "master" we need to use the "latest" endpoint, otherwise, we simply return null
|
|
||||||
if [[ "${2}" == "master" ]]; then
|
|
||||||
curl -s "https://api.github.com/repos/pi-hole/${1}/releases/latest" 2>/dev/null | jq --raw-output .tag_name || echo "null"
|
|
||||||
else
|
|
||||||
echo "null"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_remote_hash() {
|
if [[ "$3" == "reboot" ]]; then
|
||||||
git ls-remote "https://github.com/pi-hole/${1}" --tags "${2}" | awk '{print substr($0, 1,8);}' || echo "null"
|
sleep 30
|
||||||
}
|
|
||||||
|
|
||||||
# Source the utils file for addOrEditKeyValPair()
|
|
||||||
# shellcheck source="./advanced/Scripts/utils.sh"
|
|
||||||
. /opt/pihole/utils.sh
|
|
||||||
|
|
||||||
ADMIN_INTERFACE_DIR=$(getFTLConfigValue "webserver.paths.webroot")$(getFTLConfigValue "webserver.paths.webhome")
|
|
||||||
readonly ADMIN_INTERFACE_DIR
|
|
||||||
|
|
||||||
# Remove the below three legacy files if they exist
|
|
||||||
rm -f "/etc/pihole/GitHubVersions"
|
|
||||||
rm -f "/etc/pihole/localbranches"
|
|
||||||
rm -f "/etc/pihole/localversions"
|
|
||||||
|
|
||||||
VERSION_FILE="/etc/pihole/versions"
|
|
||||||
|
|
||||||
# Truncates the file to zero length if it exists to clear it up, otherwise creates an empty file.
|
|
||||||
truncate -s 0 "${VERSION_FILE}"
|
|
||||||
chmod 644 "${VERSION_FILE}"
|
|
||||||
|
|
||||||
# if /pihole.docker.tag file exists, we will use it's value later in this script
|
|
||||||
DOCKER_TAG=$(cat /pihole.docker.tag 2>/dev/null)
|
|
||||||
release_regex='^([0-9]+\.){1,2}(\*|[0-9]+)(-.*)?$'
|
|
||||||
regex=$release_regex'|(^nightly$)|(^dev.*$)'
|
|
||||||
if [[ ! "${DOCKER_TAG}" =~ $regex ]]; then
|
|
||||||
# DOCKER_TAG does not match the pattern (see https://regex101.com/r/RsENuz/1), so unset it.
|
|
||||||
unset DOCKER_TAG
|
|
||||||
fi
|
|
||||||
|
|
||||||
# used in cronjob
|
|
||||||
if [[ "$1" == "reboot" ]]; then
|
|
||||||
sleep 30
|
|
||||||
fi
|
|
||||||
|
|
||||||
# get Core versions
|
|
||||||
|
|
||||||
CORE_VERSION="$(get_local_version /etc/.pihole)"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "CORE_VERSION" "${CORE_VERSION}"
|
|
||||||
|
|
||||||
CORE_BRANCH="$(get_local_branch /etc/.pihole)"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "CORE_BRANCH" "${CORE_BRANCH}"
|
|
||||||
|
|
||||||
CORE_HASH="$(get_local_hash /etc/.pihole)"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "CORE_HASH" "${CORE_HASH}"
|
|
||||||
|
|
||||||
GITHUB_CORE_VERSION="$(get_remote_version pi-hole "${CORE_BRANCH}")"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_CORE_VERSION" "${GITHUB_CORE_VERSION}"
|
|
||||||
|
|
||||||
GITHUB_CORE_HASH="$(get_remote_hash pi-hole "${CORE_BRANCH}")"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_CORE_HASH" "${GITHUB_CORE_HASH}"
|
|
||||||
|
|
||||||
# get Web versions
|
|
||||||
|
|
||||||
WEB_VERSION="$(get_local_version "${ADMIN_INTERFACE_DIR}")"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "WEB_VERSION" "${WEB_VERSION}"
|
|
||||||
|
|
||||||
WEB_BRANCH="$(get_local_branch "${ADMIN_INTERFACE_DIR}")"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "WEB_BRANCH" "${WEB_BRANCH}"
|
|
||||||
|
|
||||||
WEB_HASH="$(get_local_hash "${ADMIN_INTERFACE_DIR}")"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "WEB_HASH" "${WEB_HASH}"
|
|
||||||
|
|
||||||
GITHUB_WEB_VERSION="$(get_remote_version web "${WEB_BRANCH}")"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_WEB_VERSION" "${GITHUB_WEB_VERSION}"
|
|
||||||
|
|
||||||
GITHUB_WEB_HASH="$(get_remote_hash web "${WEB_BRANCH}")"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_WEB_HASH" "${GITHUB_WEB_HASH}"
|
|
||||||
|
|
||||||
# get FTL versions
|
|
||||||
|
|
||||||
FTL_VERSION="$(pihole-FTL version)"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "FTL_VERSION" "${FTL_VERSION}"
|
|
||||||
|
|
||||||
FTL_BRANCH="$(pihole-FTL branch)"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "FTL_BRANCH" "${FTL_BRANCH}"
|
|
||||||
|
|
||||||
FTL_HASH="$(pihole-FTL --hash)"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "FTL_HASH" "${FTL_HASH}"
|
|
||||||
|
|
||||||
GITHUB_FTL_VERSION="$(get_remote_version FTL "${FTL_BRANCH}")"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_FTL_VERSION" "${GITHUB_FTL_VERSION}"
|
|
||||||
|
|
||||||
GITHUB_FTL_HASH="$(get_remote_hash FTL "${FTL_BRANCH}")"
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_FTL_HASH" "${GITHUB_FTL_HASH}"
|
|
||||||
|
|
||||||
# get Docker versions
|
|
||||||
|
|
||||||
if [[ "${DOCKER_TAG}" ]]; then
|
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "DOCKER_VERSION" "${DOCKER_TAG}"
|
|
||||||
|
|
||||||
# Remote version check only if the tag is a valid release version
|
|
||||||
docker_branch=""
|
|
||||||
if [[ "${DOCKER_TAG}" =~ $release_regex ]]; then
|
|
||||||
docker_branch="master"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
GITHUB_DOCKER_VERSION="$(get_remote_version docker-pi-hole "${docker_branch}")"
|
GITHUB_VERSION_FILE="/etc/pihole/GitHubVersions"
|
||||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_DOCKER_VERSION" "${GITHUB_DOCKER_VERSION}"
|
|
||||||
|
GITHUB_CORE_VERSION="$(json_extract tag_name "$(curl -s 'https://api.github.com/repos/pi-hole/pi-hole/releases/latest' 2> /dev/null)")"
|
||||||
|
echo -n "${GITHUB_CORE_VERSION}" > "${GITHUB_VERSION_FILE}"
|
||||||
|
chmod 644 "${GITHUB_VERSION_FILE}"
|
||||||
|
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
|
GITHUB_WEB_VERSION="$(json_extract tag_name "$(curl -s 'https://api.github.com/repos/pi-hole/AdminLTE/releases/latest' 2> /dev/null)")"
|
||||||
|
echo -n " ${GITHUB_WEB_VERSION}" >> "${GITHUB_VERSION_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
GITHUB_FTL_VERSION="$(json_extract tag_name "$(curl -s 'https://api.github.com/repos/pi-hole/FTL/releases/latest' 2> /dev/null)")"
|
||||||
|
echo -n " ${GITHUB_FTL_VERSION}" >> "${GITHUB_VERSION_FILE}"
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
LOCAL_BRANCH_FILE="/etc/pihole/localbranches"
|
||||||
|
|
||||||
|
CORE_BRANCH="$(get_local_branch /etc/.pihole)"
|
||||||
|
echo -n "${CORE_BRANCH}" > "${LOCAL_BRANCH_FILE}"
|
||||||
|
chmod 644 "${LOCAL_BRANCH_FILE}"
|
||||||
|
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
|
WEB_BRANCH="$(get_local_branch /var/www/html/admin)"
|
||||||
|
echo -n " ${WEB_BRANCH}" >> "${LOCAL_BRANCH_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
FTL_BRANCH="$(pihole-FTL branch)"
|
||||||
|
echo -n " ${FTL_BRANCH}" >> "${LOCAL_BRANCH_FILE}"
|
||||||
|
|
||||||
|
LOCAL_VERSION_FILE="/etc/pihole/localversions"
|
||||||
|
|
||||||
|
CORE_VERSION="$(get_local_version /etc/.pihole)"
|
||||||
|
echo -n "${CORE_VERSION}" > "${LOCAL_VERSION_FILE}"
|
||||||
|
chmod 644 "${LOCAL_VERSION_FILE}"
|
||||||
|
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
|
WEB_VERSION="$(get_local_version /var/www/html/admin)"
|
||||||
|
echo -n " ${WEB_VERSION}" >> "${LOCAL_VERSION_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
FTL_VERSION="$(pihole-FTL version)"
|
||||||
|
echo -n " ${FTL_VERSION}" >> "${LOCAL_VERSION_FILE}"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# 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 should be grouped with other similar functions
|
|
||||||
# - Functions must be documented
|
|
||||||
# - New functions must have a test added for them in test/test_any_utils.py
|
|
||||||
|
|
||||||
#######################
|
|
||||||
# Takes Three arguments: file, key, and value.
|
|
||||||
#
|
|
||||||
# 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:
|
|
||||||
# addOrEditKeyValPair "/etc/pihole/setupVars.conf" "BLOCKING_ENABLED" "true"
|
|
||||||
#######################
|
|
||||||
addOrEditKeyValPair() {
|
|
||||||
local file="${1}"
|
|
||||||
local key="${2}"
|
|
||||||
local value="${3}"
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
#######################
|
|
||||||
# returns FTL's PID based on the content of the pihole-FTL.pid file
|
|
||||||
#
|
|
||||||
# Takes one argument: path to pihole-FTL.pid
|
|
||||||
# Example getFTLPID "/run/pihole-FTL.pid"
|
|
||||||
#######################
|
|
||||||
getFTLPID() {
|
|
||||||
local FTL_PID_FILE="${1}"
|
|
||||||
local FTL_PID
|
|
||||||
|
|
||||||
if [ -s "${FTL_PID_FILE}" ]; then
|
|
||||||
# -s: FILE exists and has a size greater than zero
|
|
||||||
FTL_PID="$(cat "${FTL_PID_FILE}")"
|
|
||||||
# Exploit prevention: unset the variable if there is malicious content
|
|
||||||
# Verify that the value read from the file is numeric
|
|
||||||
expr "${FTL_PID}" : "[^[:digit:]]" > /dev/null && unset FTL_PID
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If FTL is not running, or the PID file contains malicious stuff, substitute
|
|
||||||
# negative PID to signal this
|
|
||||||
FTL_PID=${FTL_PID:=-1}
|
|
||||||
echo "${FTL_PID}"
|
|
||||||
}
|
|
||||||
|
|
||||||
#######################
|
|
||||||
# returns value from FTLs config file using pihole-FTL --config
|
|
||||||
#
|
|
||||||
# Takes one argument: key
|
|
||||||
# Example getFTLConfigValue dns.piholePTR
|
|
||||||
#######################
|
|
||||||
getFTLConfigValue(){
|
|
||||||
# Pipe to cat to avoid pihole-FTL assuming this is an interactive command
|
|
||||||
# returning colored output.
|
|
||||||
pihole-FTL --config -q "${1}" | cat
|
|
||||||
}
|
|
||||||
|
|
||||||
#######################
|
|
||||||
# sets value in FTLs config file using pihole-FTL --config
|
|
||||||
#
|
|
||||||
# Takes two arguments: key and value
|
|
||||||
# Example setFTLConfigValue dns.piholePTR PI.HOLE
|
|
||||||
#
|
|
||||||
# Note, for complex values such as dns.upstreams, you should wrap the value in single quotes:
|
|
||||||
# setFTLConfigValue dns.upstreams '[ "8.8.8.8" , "8.8.4.4" ]'
|
|
||||||
#######################
|
|
||||||
setFTLConfigValue(){
|
|
||||||
local err
|
|
||||||
{ pihole-FTL --config "${1}" "${2}" >/dev/null; err="$?"; } || true
|
|
||||||
|
|
||||||
case $err in
|
|
||||||
0) ;;
|
|
||||||
5)
|
|
||||||
# FTL returns 5 if the value was set by an environment variable and is therefore read-only
|
|
||||||
printf " %s %s set by environment variable. Please unset it to use this function\n" "${CROSS}" "${1}";
|
|
||||||
exit 5;;
|
|
||||||
*)
|
|
||||||
printf " %s Failed to set %s. Try with sudo power\n" "${CROSS}" "${1}"
|
|
||||||
exit 1
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env bash
|
||||||
# Pi-hole: A black hole for Internet advertisements
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
# Network-wide ad blocking via your own hardware.
|
# Network-wide ad blocking via your own hardware.
|
||||||
@@ -8,56 +8,169 @@
|
|||||||
# This file is copyright under the latest version of the EUPL.
|
# This file is copyright under the latest version of the EUPL.
|
||||||
# Please see LICENSE file for your rights under this license.
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
# Source the versions file populated by updatechecker.sh
|
# Variables
|
||||||
cachedVersions="/etc/pihole/versions"
|
DEFAULT="-1"
|
||||||
|
COREGITDIR="/etc/.pihole/"
|
||||||
|
WEBGITDIR="/var/www/html/admin/"
|
||||||
|
|
||||||
if [ -f ${cachedVersions} ]; then
|
getLocalVersion() {
|
||||||
# shellcheck source=/dev/null
|
# FTL requires a different method
|
||||||
. "${cachedVersions}"
|
if [[ "$1" == "FTL" ]]; then
|
||||||
else
|
pihole-FTL version
|
||||||
echo "Could not find /etc/pihole/versions. Running update now."
|
return 0
|
||||||
pihole updatechecker
|
fi
|
||||||
# shellcheck source=/dev/null
|
|
||||||
. "${cachedVersions}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Convert "null" or empty values to "N/A" for display
|
# Get the tagged version of the local repository
|
||||||
normalize_version() {
|
local directory="${1}"
|
||||||
if [ -z "${1}" ] || [ "${1}" = "null" ]; then
|
local version
|
||||||
|
|
||||||
|
cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
|
||||||
|
version=$(git describe --tags --always || echo "$DEFAULT")
|
||||||
|
if [[ "${version}" =~ ^v ]]; then
|
||||||
|
echo "${version}"
|
||||||
|
elif [[ "${version}" == "${DEFAULT}" ]]; then
|
||||||
|
echo "ERROR"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
echo "Untagged"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
getLocalHash() {
|
||||||
|
# Local FTL hash does not exist on filesystem
|
||||||
|
if [[ "$1" == "FTL" ]]; then
|
||||||
echo "N/A"
|
echo "N/A"
|
||||||
else
|
return 0
|
||||||
echo "${1}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Get the short hash of the local repository
|
||||||
|
local directory="${1}"
|
||||||
|
local hash
|
||||||
|
|
||||||
|
cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
|
||||||
|
hash=$(git rev-parse --short HEAD || echo "$DEFAULT")
|
||||||
|
if [[ "${hash}" == "${DEFAULT}" ]]; then
|
||||||
|
echo "ERROR"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
echo "${hash}"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
getRemoteHash(){
|
||||||
local details
|
# Remote FTL hash is not applicable
|
||||||
details=false
|
if [[ "$1" == "FTL" ]]; then
|
||||||
|
echo "N/A"
|
||||||
# Automatically show detailed information if
|
return 0
|
||||||
# at least one of the components is not on master branch
|
|
||||||
if [ ! "${CORE_BRANCH}" = "master" ] || [ ! "${WEB_BRANCH}" = "master" ] || [ ! "${FTL_BRANCH}" = "master" ]; then
|
|
||||||
details=true
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${details}" = true ]; then
|
local daemon="${1}"
|
||||||
echo "Core"
|
local branch="${2}"
|
||||||
echo " Version is $(normalize_version "${CORE_VERSION}") (Latest: $(normalize_version "${GITHUB_CORE_VERSION}"))"
|
|
||||||
echo " Branch is $(normalize_version "${CORE_BRANCH}")"
|
hash=$(git ls-remote --heads "https://github.com/pi-hole/${daemon}" | \
|
||||||
echo " Hash is $(normalize_version "${CORE_HASH}") (Latest: $(normalize_version "${GITHUB_CORE_HASH}"))"
|
awk -v bra="$branch" '$0~bra {print substr($0,0,8);exit}')
|
||||||
echo "Web"
|
if [[ -n "$hash" ]]; then
|
||||||
echo " Version is $(normalize_version "${WEB_VERSION}") (Latest: $(normalize_version "${GITHUB_WEB_VERSION}"))"
|
echo "$hash"
|
||||||
echo " Branch is $(normalize_version "${WEB_BRANCH}")"
|
|
||||||
echo " Hash is $(normalize_version "${WEB_HASH}") (Latest: $(normalize_version "${GITHUB_WEB_HASH}"))"
|
|
||||||
echo "FTL"
|
|
||||||
echo " Version is $(normalize_version "${FTL_VERSION}") (Latest: $(normalize_version "${GITHUB_FTL_VERSION}"))"
|
|
||||||
echo " Branch is $(normalize_version "${FTL_BRANCH}")"
|
|
||||||
echo " Hash is $(normalize_version "${FTL_HASH}") (Latest: $(normalize_version "${GITHUB_FTL_HASH}"))"
|
|
||||||
else
|
else
|
||||||
echo "Core version is $(normalize_version "${CORE_VERSION}") (Latest: $(normalize_version "${GITHUB_CORE_VERSION}"))"
|
echo "ERROR"
|
||||||
echo "Web version is $(normalize_version "${WEB_VERSION}") (Latest: $(normalize_version "${GITHUB_WEB_VERSION}"))"
|
return 1
|
||||||
echo "FTL version is $(normalize_version "${FTL_VERSION}") (Latest: $(normalize_version "${GITHUB_FTL_VERSION}"))"
|
|
||||||
fi
|
fi
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
main
|
getRemoteVersion(){
|
||||||
|
# Get the version from the remote origin
|
||||||
|
local daemon="${1}"
|
||||||
|
local version
|
||||||
|
|
||||||
|
version=$(curl --silent --fail "https://api.github.com/repos/pi-hole/${daemon}/releases/latest" | \
|
||||||
|
awk -F: '$1 ~/tag_name/ { print $2 }' | \
|
||||||
|
tr -cd '[[:alnum:]]._-')
|
||||||
|
if [[ "${version}" =~ ^v ]]; then
|
||||||
|
echo "${version}"
|
||||||
|
else
|
||||||
|
echo "ERROR"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
versionOutput() {
|
||||||
|
[[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
|
||||||
|
[[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
|
||||||
|
[[ "$1" == "FTL" ]] && GITDIR="FTL"
|
||||||
|
|
||||||
|
[[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $GITDIR)
|
||||||
|
[[ "$2" == "-l" ]] || [[ "$2" == "--latest" ]] || [[ -z "$2" ]] && latest=$(getRemoteVersion "$1")
|
||||||
|
if [[ "$2" == "-h" ]] || [[ "$2" == "--hash" ]]; then
|
||||||
|
[[ "$3" == "-c" ]] || [[ "$3" == "--current" ]] || [[ -z "$3" ]] && curHash=$(getLocalHash "$GITDIR")
|
||||||
|
[[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$current" ]] && [[ -n "$latest" ]]; then
|
||||||
|
output="${1^} version is $current (Latest: $latest)"
|
||||||
|
elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then
|
||||||
|
output="Current ${1^} version is $current"
|
||||||
|
elif [[ -z "$current" ]] && [[ -n "$latest" ]]; then
|
||||||
|
output="Latest ${1^} version is $latest"
|
||||||
|
elif [[ "$curHash" == "N/A" ]] || [[ "$latHash" == "N/A" ]]; then
|
||||||
|
output="${1^} hash is not applicable"
|
||||||
|
elif [[ -n "$curHash" ]] && [[ -n "$latHash" ]]; then
|
||||||
|
output="${1^} hash is $curHash (Latest: $latHash)"
|
||||||
|
elif [[ -n "$curHash" ]] && [[ -z "$latHash" ]]; then
|
||||||
|
output="Current ${1^} hash is $curHash"
|
||||||
|
elif [[ -z "$curHash" ]] && [[ -n "$latHash" ]]; then
|
||||||
|
output="Latest ${1^} hash is $latHash"
|
||||||
|
else
|
||||||
|
errorOutput
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -n "$output" ]] && echo " $output"
|
||||||
|
}
|
||||||
|
|
||||||
|
errorOutput() {
|
||||||
|
echo " Invalid Option! Try 'pihole -v --help' for more information."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultOutput() {
|
||||||
|
# Source the setupvars config file
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source /etc/pihole/setupVars.conf
|
||||||
|
|
||||||
|
versionOutput "pi-hole" "$@"
|
||||||
|
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
|
versionOutput "AdminLTE" "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
versionOutput "FTL" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
helpFunc() {
|
||||||
|
echo "Usage: pihole -v [repo | option] [option]
|
||||||
|
Example: 'pihole -v -p -l'
|
||||||
|
Show Pi-hole, Admin Console & FTL versions
|
||||||
|
|
||||||
|
Repositories:
|
||||||
|
-p, --pihole Only retrieve info regarding Pi-hole repository
|
||||||
|
-a, --admin Only retrieve info regarding AdminLTE repository
|
||||||
|
-f, --ftl Only retrieve info regarding FTL repository
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-c, --current Return the current version
|
||||||
|
-l, --latest Return the latest version
|
||||||
|
--hash Return the Github hash from your local repositories
|
||||||
|
-h, --help Show this help dialog"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1}" in
|
||||||
|
"-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";;
|
||||||
|
"-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";;
|
||||||
|
"-f" | "--ftl" ) shift; versionOutput "FTL" "$@";;
|
||||||
|
"-h" | "--help" ) helpFunc;;
|
||||||
|
* ) defaultOutput "$@";;
|
||||||
|
esac
|
||||||
|
|||||||
632
advanced/Scripts/webpage.sh
Executable file
632
advanced/Scripts/webpage.sh
Executable file
@@ -0,0 +1,632 @@
|
|||||||
|
#!/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.
|
||||||
|
#
|
||||||
|
# Web interface settings
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
readonly setupVars="/etc/pihole/setupVars.conf"
|
||||||
|
readonly dnsmasqconfig="/etc/dnsmasq.d/01-pihole.conf"
|
||||||
|
readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf"
|
||||||
|
readonly FTLconf="/etc/pihole/pihole-FTL.conf"
|
||||||
|
# 03 -> wildcards
|
||||||
|
readonly dhcpstaticconfig="/etc/dnsmasq.d/04-pihole-static-dhcp.conf"
|
||||||
|
|
||||||
|
readonly gravityDBfile="/etc/pihole/gravity.db"
|
||||||
|
|
||||||
|
coltable="/opt/pihole/COL_TABLE"
|
||||||
|
if [[ -f ${coltable} ]]; then
|
||||||
|
source ${coltable}
|
||||||
|
fi
|
||||||
|
|
||||||
|
helpFunc() {
|
||||||
|
echo "Usage: pihole -a [options]
|
||||||
|
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
|
||||||
|
-r, hostrecord Add a name to the DNS associated to an IPv4/IPv6 address
|
||||||
|
-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() {
|
||||||
|
echo "${1}=${2}" >> "${setupVars}"
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_setting() {
|
||||||
|
sed -i "/${1}/d" "${setupVars}"
|
||||||
|
}
|
||||||
|
|
||||||
|
change_setting() {
|
||||||
|
delete_setting "${1}"
|
||||||
|
add_setting "${1}" "${2}"
|
||||||
|
}
|
||||||
|
|
||||||
|
addFTLsetting() {
|
||||||
|
echo "${1}=${2}" >> "${FTLconf}"
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteFTLsetting() {
|
||||||
|
sed -i "/${1}/d" "${FTLconf}"
|
||||||
|
}
|
||||||
|
|
||||||
|
changeFTLsetting() {
|
||||||
|
deleteFTLsetting "${1}"
|
||||||
|
addFTLsetting "${1}" "${2}"
|
||||||
|
}
|
||||||
|
|
||||||
|
add_dnsmasq_setting() {
|
||||||
|
if [[ "${2}" != "" ]]; then
|
||||||
|
echo "${1}=${2}" >> "${dnsmasqconfig}"
|
||||||
|
else
|
||||||
|
echo "${1}" >> "${dnsmasqconfig}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_dnsmasq_setting() {
|
||||||
|
sed -i "/${1}/d" "${dnsmasqconfig}"
|
||||||
|
}
|
||||||
|
|
||||||
|
SetTemperatureUnit() {
|
||||||
|
change_setting "TEMPERATUREUNIT" "${unit}"
|
||||||
|
echo -e " ${TICK} Set temperature unit to ${unit}"
|
||||||
|
}
|
||||||
|
|
||||||
|
HashPassword() {
|
||||||
|
# Compute password hash twice to avoid rainbow table vulnerability
|
||||||
|
return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//')
|
||||||
|
return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//')
|
||||||
|
echo ${return}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetWebPassword() {
|
||||||
|
if [ "${SUDO_USER}" == "www-data" ]; then
|
||||||
|
echo "Security measure: user www-data is not allowed to change webUI password!"
|
||||||
|
echo "Exiting"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${SUDO_USER}" == "lighttpd" ]; then
|
||||||
|
echo "Security measure: user lighttpd is not allowed to change webUI password!"
|
||||||
|
echo "Exiting"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( ${#args[2]} > 0 )) ; then
|
||||||
|
readonly PASSWORD="${args[2]}"
|
||||||
|
readonly CONFIRM="${PASSWORD}"
|
||||||
|
else
|
||||||
|
# Prevents a bug if the user presses Ctrl+C and it continues to hide the text typed.
|
||||||
|
# So we reset the terminal via stty if the user does press Ctrl+C
|
||||||
|
trap '{ echo -e "\nNo password will be set" ; stty sane ; exit 1; }' INT
|
||||||
|
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
|
||||||
|
|
||||||
|
read -s -r -p "Confirm Password: " CONFIRM
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
|
||||||
|
# We do not wrap this in brackets, otherwise BASH will expand any appropriate syntax
|
||||||
|
hash=$(HashPassword "$PASSWORD")
|
||||||
|
# Save hash to file
|
||||||
|
change_setting "WEBPASSWORD" "${hash}"
|
||||||
|
echo -e " ${TICK} New password set"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} Passwords don't match. Your password has not been changed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessDNSSettings() {
|
||||||
|
source "${setupVars}"
|
||||||
|
|
||||||
|
delete_dnsmasq_setting "server"
|
||||||
|
|
||||||
|
COUNTER=1
|
||||||
|
while [[ 1 ]]; do
|
||||||
|
var=PIHOLE_DNS_${COUNTER}
|
||||||
|
if [ -z "${!var}" ]; then
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
add_dnsmasq_setting "server" "${!var}"
|
||||||
|
let COUNTER=COUNTER+1
|
||||||
|
done
|
||||||
|
|
||||||
|
# The option LOCAL_DNS_PORT is deprecated
|
||||||
|
# We apply it once more, and then convert it into the current format
|
||||||
|
if [ ! -z "${LOCAL_DNS_PORT}" ]; then
|
||||||
|
add_dnsmasq_setting "server" "127.0.0.1#${LOCAL_DNS_PORT}"
|
||||||
|
add_setting "PIHOLE_DNS_${COUNTER}" "127.0.0.1#${LOCAL_DNS_PORT}"
|
||||||
|
delete_setting "LOCAL_DNS_PORT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
delete_dnsmasq_setting "domain-needed"
|
||||||
|
|
||||||
|
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
|
||||||
|
add_dnsmasq_setting "domain-needed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
delete_dnsmasq_setting "bogus-priv"
|
||||||
|
|
||||||
|
if [[ "${DNS_BOGUS_PRIV}" == true ]]; then
|
||||||
|
add_dnsmasq_setting "bogus-priv"
|
||||||
|
fi
|
||||||
|
|
||||||
|
delete_dnsmasq_setting "dnssec"
|
||||||
|
delete_dnsmasq_setting "trust-anchor="
|
||||||
|
|
||||||
|
if [[ "${DNSSEC}" == true ]]; then
|
||||||
|
echo "dnssec
|
||||||
|
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
|
||||||
|
trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D
|
||||||
|
" >> "${dnsmasqconfig}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
delete_dnsmasq_setting "host-record"
|
||||||
|
|
||||||
|
if [ ! -z "${HOSTRECORD}" ]; then
|
||||||
|
add_dnsmasq_setting "host-record" "${HOSTRECORD}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Setup interface listening behavior of dnsmasq
|
||||||
|
delete_dnsmasq_setting "interface"
|
||||||
|
delete_dnsmasq_setting "local-service"
|
||||||
|
|
||||||
|
if [[ "${DNSMASQ_LISTENING}" == "all" ]]; then
|
||||||
|
# Listen on all interfaces, permit all origins
|
||||||
|
add_dnsmasq_setting "except-interface" "nonexisting"
|
||||||
|
elif [[ "${DNSMASQ_LISTENING}" == "local" ]]; then
|
||||||
|
# Listen only on all interfaces, but only local subnets
|
||||||
|
add_dnsmasq_setting "local-service"
|
||||||
|
else
|
||||||
|
# Listen only on one interface
|
||||||
|
# Use eth0 as fallback interface if interface is missing in setupVars.conf
|
||||||
|
if [ -z "${PIHOLE_INTERFACE}" ]; then
|
||||||
|
PIHOLE_INTERFACE="eth0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${CONDITIONAL_FORWARDING}" == true ]]; then
|
||||||
|
add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_DOMAIN}/${CONDITIONAL_FORWARDING_IP}"
|
||||||
|
add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_REVERSE}/${CONDITIONAL_FORWARDING_IP}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDNSServers() {
|
||||||
|
# Save setting to file
|
||||||
|
delete_setting "PIHOLE_DNS"
|
||||||
|
IFS=',' read -r -a array <<< "${args[2]}"
|
||||||
|
for index in "${!array[@]}"
|
||||||
|
do
|
||||||
|
add_setting "PIHOLE_DNS_$((index+1))" "${array[index]}"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "${args[3]}" == "domain-needed" ]]; then
|
||||||
|
change_setting "DNS_FQDN_REQUIRED" "true"
|
||||||
|
else
|
||||||
|
change_setting "DNS_FQDN_REQUIRED" "false"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${args[4]}" == "bogus-priv" ]]; then
|
||||||
|
change_setting "DNS_BOGUS_PRIV" "true"
|
||||||
|
else
|
||||||
|
change_setting "DNS_BOGUS_PRIV" "false"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${args[5]}" == "dnssec" ]]; then
|
||||||
|
change_setting "DNSSEC" "true"
|
||||||
|
else
|
||||||
|
change_setting "DNSSEC" "false"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${args[6]}" == "conditional_forwarding" ]]; then
|
||||||
|
change_setting "CONDITIONAL_FORWARDING" "true"
|
||||||
|
change_setting "CONDITIONAL_FORWARDING_IP" "${args[7]}"
|
||||||
|
change_setting "CONDITIONAL_FORWARDING_DOMAIN" "${args[8]}"
|
||||||
|
change_setting "CONDITIONAL_FORWARDING_REVERSE" "${args[9]}"
|
||||||
|
else
|
||||||
|
change_setting "CONDITIONAL_FORWARDING" "false"
|
||||||
|
delete_setting "CONDITIONAL_FORWARDING_IP"
|
||||||
|
delete_setting "CONDITIONAL_FORWARDING_DOMAIN"
|
||||||
|
delete_setting "CONDITIONAL_FORWARDING_REVERSE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ProcessDNSSettings
|
||||||
|
|
||||||
|
# Restart dnsmasq to load new configuration
|
||||||
|
RestartDNS
|
||||||
|
}
|
||||||
|
|
||||||
|
SetExcludeDomains() {
|
||||||
|
change_setting "API_EXCLUDE_DOMAINS" "${args[2]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
SetExcludeClients() {
|
||||||
|
change_setting "API_EXCLUDE_CLIENTS" "${args[2]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
Poweroff(){
|
||||||
|
nohup bash -c "sleep 5; poweroff" &> /dev/null </dev/null &
|
||||||
|
}
|
||||||
|
|
||||||
|
Reboot() {
|
||||||
|
nohup bash -c "sleep 5; reboot" &> /dev/null </dev/null &
|
||||||
|
}
|
||||||
|
|
||||||
|
RestartDNS() {
|
||||||
|
/usr/local/bin/pihole restartdns
|
||||||
|
}
|
||||||
|
|
||||||
|
SetQueryLogOptions() {
|
||||||
|
change_setting "API_QUERY_LOG_SHOW" "${args[2]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessDHCPSettings() {
|
||||||
|
source "${setupVars}"
|
||||||
|
|
||||||
|
if [[ "${DHCP_ACTIVE}" == "true" ]]; then
|
||||||
|
interface="${PIHOLE_INTERFACE}"
|
||||||
|
|
||||||
|
# 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 [[ "${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 "###############################################################################
|
||||||
|
# DHCP SERVER CONFIG FILE AUTOMATICALLY POPULATED BY PI-HOLE WEB INTERFACE. #
|
||||||
|
# ANY CHANGES MADE TO THIS FILE WILL BE LOST ON CHANGE #
|
||||||
|
###############################################################################
|
||||||
|
dhcp-authoritative
|
||||||
|
dhcp-range=${DHCP_START},${DHCP_END},${leasetime}
|
||||||
|
dhcp-option=option:router,${DHCP_ROUTER}
|
||||||
|
dhcp-leasefile=/etc/pihole/dhcp.leases
|
||||||
|
#quiet-dhcp
|
||||||
|
" > "${dhcpconfig}"
|
||||||
|
chmod 644 "${dhcpconfig}"
|
||||||
|
|
||||||
|
if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
|
||||||
|
echo "domain=${PIHOLE_DOMAIN}" >> "${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
|
||||||
|
#enable-ra
|
||||||
|
dhcp-option=option6:dns-server,[::]
|
||||||
|
dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,${leasetime}
|
||||||
|
ra-param=*,0,0
|
||||||
|
" >> "${dhcpconfig}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
if [[ -f "${dhcpconfig}" ]]; then
|
||||||
|
rm "${dhcpconfig}" &> /dev/null
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
EnableDHCP() {
|
||||||
|
change_setting "DHCP_ACTIVE" "true"
|
||||||
|
change_setting "DHCP_START" "${args[2]}"
|
||||||
|
change_setting "DHCP_END" "${args[3]}"
|
||||||
|
change_setting "DHCP_ROUTER" "${args[4]}"
|
||||||
|
change_setting "DHCP_LEASETIME" "${args[5]}"
|
||||||
|
change_setting "PIHOLE_DOMAIN" "${args[6]}"
|
||||||
|
change_setting "DHCP_IPv6" "${args[7]}"
|
||||||
|
change_setting "DHCP_rapid_commit" "${args[8]}"
|
||||||
|
|
||||||
|
# Remove possible old setting from file
|
||||||
|
delete_dnsmasq_setting "dhcp-"
|
||||||
|
delete_dnsmasq_setting "quiet-dhcp"
|
||||||
|
|
||||||
|
# If a DHCP client claims that its name is "wpad", ignore that.
|
||||||
|
# This fixes a security hole. see CERT Vulnerability VU#598349
|
||||||
|
# We also ignore "localhost" as Windows behaves strangely if a
|
||||||
|
# device claims this host name
|
||||||
|
add_dnsmasq_setting "dhcp-name-match=set:hostname-ignore,wpad
|
||||||
|
dhcp-name-match=set:hostname-ignore,localhost
|
||||||
|
dhcp-ignore-names=tag:hostname-ignore"
|
||||||
|
|
||||||
|
ProcessDHCPSettings
|
||||||
|
|
||||||
|
RestartDNS
|
||||||
|
}
|
||||||
|
|
||||||
|
DisableDHCP() {
|
||||||
|
change_setting "DHCP_ACTIVE" "false"
|
||||||
|
|
||||||
|
# Remove possible old setting from file
|
||||||
|
delete_dnsmasq_setting "dhcp-"
|
||||||
|
delete_dnsmasq_setting "quiet-dhcp"
|
||||||
|
|
||||||
|
ProcessDHCPSettings
|
||||||
|
|
||||||
|
RestartDNS
|
||||||
|
}
|
||||||
|
|
||||||
|
SetWebUILayout() {
|
||||||
|
change_setting "WEBUIBOXEDLAYOUT" "${args[2]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomizeAdLists() {
|
||||||
|
local address
|
||||||
|
address="${args[3]}"
|
||||||
|
|
||||||
|
if [[ "${args[2]}" == "enable" ]]; then
|
||||||
|
sqlite3 "${gravityDBfile}" "UPDATE adlist SET enabled = 1 WHERE address = '${address}'"
|
||||||
|
elif [[ "${args[2]}" == "disable" ]]; then
|
||||||
|
sqlite3 "${gravityDBfile}" "UPDATE adlist SET enabled = 0 WHERE address = '${address}'"
|
||||||
|
elif [[ "${args[2]}" == "add" ]]; then
|
||||||
|
sqlite3 "${gravityDBfile}" "INSERT OR IGNORE INTO adlist (address) VALUES ('${address}')"
|
||||||
|
elif [[ "${args[2]}" == "del" ]]; then
|
||||||
|
sqlite3 "${gravityDBfile}" "DELETE FROM adlist WHERE address = '${address}'"
|
||||||
|
else
|
||||||
|
echo "Not permitted"
|
||||||
|
return 1
|
||||||
|
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]}"
|
||||||
|
host="${args[4]}"
|
||||||
|
|
||||||
|
if [[ "${ip}" == "noip" ]]; then
|
||||||
|
# Static host name
|
||||||
|
echo "dhcp-host=${mac},${host}" >> "${dhcpstaticconfig}"
|
||||||
|
elif [[ "${host}" == "nohost" ]]; then
|
||||||
|
# Static IP
|
||||||
|
echo "dhcp-host=${mac},${ip}" >> "${dhcpstaticconfig}"
|
||||||
|
else
|
||||||
|
# Full info given
|
||||||
|
echo "dhcp-host=${mac},${ip},${host}" >> "${dhcpstaticconfig}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveDHCPStaticAddress() {
|
||||||
|
mac="${args[2]}"
|
||||||
|
sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}"
|
||||||
|
}
|
||||||
|
|
||||||
|
SetHostRecord() {
|
||||||
|
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
|
||||||
|
echo "Usage: pihole -a hostrecord <domain> [IPv4-address],[IPv6-address]
|
||||||
|
Example: 'pihole -a hostrecord home.domain.com 192.168.1.1,2001:db8:a0b:12f0::1'
|
||||||
|
Add a name to the DNS associated to an IPv4/IPv6 address
|
||||||
|
|
||||||
|
Options:
|
||||||
|
\"\" Empty: Remove host record
|
||||||
|
-h, --help Show this help dialog"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${args[3]}" ]]; then
|
||||||
|
change_setting "HOSTRECORD" "${args[2]},${args[3]}"
|
||||||
|
echo -e " ${TICK} Setting host record for ${args[2]} to ${args[3]}"
|
||||||
|
else
|
||||||
|
change_setting "HOSTRECORD" ""
|
||||||
|
echo -e " ${TICK} Removing host record"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ProcessDNSSettings
|
||||||
|
|
||||||
|
# Restart dnsmasq to load new configuration
|
||||||
|
RestartDNS
|
||||||
|
}
|
||||||
|
|
||||||
|
SetAdminEmail() {
|
||||||
|
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
|
||||||
|
echo "Usage: pihole -a email <address>
|
||||||
|
Example: 'pihole -a email admin@address.com'
|
||||||
|
Set an administrative contact address for the Block Page
|
||||||
|
|
||||||
|
Options:
|
||||||
|
\"\" Empty: Remove admin contact
|
||||||
|
-h, --help Show this help dialog"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${args[2]}" ]]; then
|
||||||
|
change_setting "ADMIN_EMAIL" "${args[2]}"
|
||||||
|
echo -e " ${TICK} Setting admin contact to ${args[2]}"
|
||||||
|
else
|
||||||
|
change_setting "ADMIN_EMAIL" ""
|
||||||
|
echo -e " ${TICK} Removing admin contact"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
SetListeningMode() {
|
||||||
|
source "${setupVars}"
|
||||||
|
|
||||||
|
if [[ "$3" == "-h" ]] || [[ "$3" == "--help" ]]; then
|
||||||
|
echo "Usage: pihole -a -i [interface]
|
||||||
|
Example: 'pihole -a -i local'
|
||||||
|
Specify dnsmasq's network interface listening behavior
|
||||||
|
|
||||||
|
Interfaces:
|
||||||
|
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
|
||||||
|
|
||||||
|
if [[ "${args[2]}" == "all" ]]; then
|
||||||
|
echo -e " ${INFO} Listening on all interfaces, permiting all origins. Please use a firewall!"
|
||||||
|
change_setting "DNSMASQ_LISTENING" "all"
|
||||||
|
elif [[ "${args[2]}" == "local" ]]; then
|
||||||
|
echo -e " ${INFO} Listening on all interfaces, permiting origins from one hop away (LAN)"
|
||||||
|
change_setting "DNSMASQ_LISTENING" "local"
|
||||||
|
else
|
||||||
|
echo -e " ${INFO} Listening only on interface ${PIHOLE_INTERFACE}"
|
||||||
|
change_setting "DNSMASQ_LISTENING" "single"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Don't restart DNS server yet because other settings
|
||||||
|
# will be applied afterwards if "-web" is set
|
||||||
|
if [[ "${args[3]}" != "-web" ]]; then
|
||||||
|
ProcessDNSSettings
|
||||||
|
# Restart dnsmasq to load new configuration
|
||||||
|
RestartDNS
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Teleporter() {
|
||||||
|
local 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()
|
||||||
|
{
|
||||||
|
local domain validDomain
|
||||||
|
# Convert to lowercase
|
||||||
|
domain="${1,,}"
|
||||||
|
validDomain=$(grep -P "^((-|_)*[a-z\\d]((-|_)*[a-z\\d])*(-|_)*)(\\.(-|_)*([a-z\\d]((-|_)*[a-z\\d])*))*$" <<< "${domain}") # Valid chars check
|
||||||
|
validDomain=$(grep -P "^[^\\.]{1,63}(\\.[^\\.]{1,63})*$" <<< "${validDomain}") # Length of each label
|
||||||
|
echo "${validDomain}"
|
||||||
|
}
|
||||||
|
|
||||||
|
addAudit()
|
||||||
|
{
|
||||||
|
shift # skip "-a"
|
||||||
|
shift # skip "audit"
|
||||||
|
local domains validDomain
|
||||||
|
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}')"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Insert only the domain here. The date_added field will be
|
||||||
|
# filled with its default value (date_added = current timestamp)
|
||||||
|
sqlite3 "${gravityDBfile}" "INSERT INTO domain_audit (domain) VALUES ${domains};"
|
||||||
|
}
|
||||||
|
|
||||||
|
clearAudit()
|
||||||
|
{
|
||||||
|
sqlite3 "${gravityDBfile}" "DELETE FROM domain_audit;"
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPrivacyLevel() {
|
||||||
|
# Set privacy level. Minimum is 0, maximum is 4
|
||||||
|
if [ "${args[2]}" -ge 0 ] && [ "${args[2]}" -le 4 ]; then
|
||||||
|
changeFTLsetting "PRIVACYLEVEL" "${args[2]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
args=("$@")
|
||||||
|
|
||||||
|
case "${args[1]}" in
|
||||||
|
"-p" | "password" ) SetWebPassword;;
|
||||||
|
"-c" | "celsius" ) unit="C"; SetTemperatureUnit;;
|
||||||
|
"-f" | "fahrenheit" ) unit="F"; SetTemperatureUnit;;
|
||||||
|
"-k" | "kelvin" ) unit="K"; SetTemperatureUnit;;
|
||||||
|
"setdns" ) SetDNSServers;;
|
||||||
|
"setexcludedomains" ) SetExcludeDomains;;
|
||||||
|
"setexcludeclients" ) SetExcludeClients;;
|
||||||
|
"poweroff" ) Poweroff;;
|
||||||
|
"reboot" ) Reboot;;
|
||||||
|
"restartdns" ) RestartDNS;;
|
||||||
|
"setquerylog" ) SetQueryLogOptions;;
|
||||||
|
"enabledhcp" ) EnableDHCP;;
|
||||||
|
"disabledhcp" ) DisableDHCP;;
|
||||||
|
"layout" ) SetWebUILayout;;
|
||||||
|
"-h" | "--help" ) helpFunc;;
|
||||||
|
"privacymode" ) SetPrivacyMode;;
|
||||||
|
"resolve" ) ResolutionSettings;;
|
||||||
|
"addstaticdhcp" ) AddDHCPStaticAddress;;
|
||||||
|
"removestaticdhcp" ) RemoveDHCPStaticAddress;;
|
||||||
|
"-r" | "hostrecord" ) SetHostRecord "$3";;
|
||||||
|
"-e" | "email" ) SetAdminEmail "$3";;
|
||||||
|
"-i" | "interface" ) SetListeningMode "$@";;
|
||||||
|
"-t" | "teleporter" ) Teleporter;;
|
||||||
|
"adlist" ) CustomizeAdLists;;
|
||||||
|
"audit" ) addAudit "$@";;
|
||||||
|
"clearaudit" ) clearAudit;;
|
||||||
|
"-l" | "privacylevel" ) SetPrivacyLevel;;
|
||||||
|
* ) helpFunc;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [[ $# = 0 ]]; then
|
||||||
|
helpFunc
|
||||||
|
fi
|
||||||
|
}
|
||||||
28
advanced/Scripts/wildcard_regex_converter.sh
Normal file
28
advanced/Scripts/wildcard_regex_converter.sh
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/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}"
|
||||||
|
}
|
||||||
@@ -1,205 +1,143 @@
|
|||||||
PRAGMA foreign_keys=OFF;
|
PRAGMA FOREIGN_KEYS=ON;
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
CREATE TABLE "group"
|
CREATE TABLE "group"
|
||||||
(
|
(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
enabled BOOLEAN NOT NULL DEFAULT 1,
|
enabled BOOLEAN NOT NULL DEFAULT 1,
|
||||||
name TEXT UNIQUE NOT NULL,
|
name TEXT NOT NULL,
|
||||||
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
description TEXT
|
||||||
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
|
||||||
description TEXT
|
|
||||||
);
|
);
|
||||||
INSERT INTO "group" (id,enabled,name,description) VALUES (0,1,'Default','The default group');
|
|
||||||
|
|
||||||
CREATE TABLE domainlist
|
CREATE TABLE whitelist
|
||||||
(
|
(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
type INTEGER NOT NULL DEFAULT 0,
|
domain TEXT UNIQUE NOT NULL,
|
||||||
domain TEXT NOT NULL,
|
enabled BOOLEAN NOT NULL DEFAULT 1,
|
||||||
enabled BOOLEAN NOT NULL DEFAULT 1,
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
comment TEXT
|
||||||
comment TEXT,
|
);
|
||||||
UNIQUE(domain, type)
|
|
||||||
|
CREATE TABLE whitelist_by_group
|
||||||
|
(
|
||||||
|
whitelist_id INTEGER NOT NULL REFERENCES whitelist (id),
|
||||||
|
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
||||||
|
PRIMARY KEY (whitelist_id, group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE blacklist
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
domain TEXT UNIQUE NOT NULL,
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE blacklist_by_group
|
||||||
|
(
|
||||||
|
blacklist_id INTEGER NOT NULL REFERENCES blacklist (id),
|
||||||
|
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
||||||
|
PRIMARY KEY (blacklist_id, group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE regex
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
domain TEXT UNIQUE NOT NULL,
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE regex_by_group
|
||||||
|
(
|
||||||
|
regex_id INTEGER NOT NULL REFERENCES regex (id),
|
||||||
|
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
||||||
|
PRIMARY KEY (regex_id, group_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE adlist
|
CREATE TABLE adlist
|
||||||
(
|
(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
address TEXT NOT NULL,
|
address TEXT UNIQUE NOT NULL,
|
||||||
enabled BOOLEAN NOT NULL DEFAULT 1,
|
enabled BOOLEAN NOT NULL DEFAULT 1,
|
||||||
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
comment TEXT,
|
comment TEXT
|
||||||
date_updated INTEGER,
|
|
||||||
number INTEGER NOT NULL DEFAULT 0,
|
|
||||||
invalid_domains INTEGER NOT NULL DEFAULT 0,
|
|
||||||
status INTEGER NOT NULL DEFAULT 0,
|
|
||||||
abp_entries INTEGER NOT NULL DEFAULT 0,
|
|
||||||
type INTEGER NOT NULL DEFAULT 0,
|
|
||||||
UNIQUE(address, type)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE adlist_by_group
|
CREATE TABLE adlist_by_group
|
||||||
(
|
(
|
||||||
adlist_id INTEGER NOT NULL REFERENCES adlist (id) ON DELETE CASCADE,
|
adlist_id INTEGER NOT NULL REFERENCES adlist (id),
|
||||||
group_id INTEGER NOT NULL REFERENCES "group" (id) ON DELETE CASCADE,
|
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
||||||
PRIMARY KEY (adlist_id, group_id)
|
PRIMARY KEY (adlist_id, group_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE gravity
|
CREATE TABLE gravity
|
||||||
(
|
(
|
||||||
domain TEXT NOT NULL,
|
domain TEXT PRIMARY KEY
|
||||||
adlist_id INTEGER NOT NULL REFERENCES adlist (id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE antigravity
|
|
||||||
(
|
|
||||||
domain TEXT NOT NULL,
|
|
||||||
adlist_id INTEGER NOT NULL REFERENCES adlist (id)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE info
|
CREATE TABLE info
|
||||||
(
|
(
|
||||||
property TEXT PRIMARY KEY,
|
property TEXT PRIMARY KEY,
|
||||||
value TEXT NOT NULL
|
value TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO "info" VALUES('version','20');
|
INSERT INTO info VALUES("version","1");
|
||||||
/* This is a flag to indicate if gravity was restored from a backup
|
|
||||||
false = not restored,
|
|
||||||
failed = restoration failed due to no backup
|
|
||||||
other string = restoration successful with the string being the backup file used */
|
|
||||||
INSERT INTO "info" VALUES('gravity_restored','false');
|
|
||||||
|
|
||||||
CREATE TABLE domainlist_by_group
|
CREATE VIEW vw_gravity AS SELECT domain
|
||||||
(
|
|
||||||
domainlist_id INTEGER NOT NULL REFERENCES domainlist (id) ON DELETE CASCADE,
|
|
||||||
group_id INTEGER NOT NULL REFERENCES "group" (id) ON DELETE CASCADE,
|
|
||||||
PRIMARY KEY (domainlist_id, group_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE client
|
|
||||||
(
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
ip TEXT NOT 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
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE client_by_group
|
|
||||||
(
|
|
||||||
client_id INTEGER NOT NULL REFERENCES client (id) ON DELETE CASCADE,
|
|
||||||
group_id INTEGER NOT NULL REFERENCES "group" (id) ON DELETE CASCADE,
|
|
||||||
PRIMARY KEY (client_id, group_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_client_update AFTER UPDATE ON client
|
|
||||||
BEGIN
|
|
||||||
UPDATE client SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE ip = NEW.ip;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_domainlist_update AFTER UPDATE ON domainlist
|
|
||||||
BEGIN
|
|
||||||
UPDATE domainlist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE domain = NEW.domain;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE VIEW vw_allowlist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 0
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
CREATE VIEW vw_denylist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 1
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
CREATE VIEW vw_regex_allowlist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 2
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
CREATE VIEW vw_regex_denylist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
|
||||||
FROM domainlist
|
|
||||||
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
|
||||||
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
|
||||||
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
|
||||||
AND domainlist.type = 3
|
|
||||||
ORDER BY domainlist.id;
|
|
||||||
|
|
||||||
CREATE VIEW vw_gravity AS SELECT domain, adlist.id AS adlist_id, adlist_by_group.group_id AS group_id
|
|
||||||
FROM gravity
|
FROM gravity
|
||||||
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = gravity.adlist_id
|
WHERE domain NOT IN (SELECT domain from vw_whitelist);
|
||||||
LEFT JOIN adlist ON adlist.id = gravity.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);
|
|
||||||
|
|
||||||
CREATE VIEW vw_antigravity AS SELECT domain, adlist.id AS adlist_id, adlist_by_group.group_id AS group_id
|
CREATE VIEW vw_whitelist AS SELECT DISTINCT domain
|
||||||
FROM antigravity
|
FROM whitelist
|
||||||
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = antigravity.adlist_id
|
LEFT JOIN whitelist_by_group ON whitelist_by_group.whitelist_id = whitelist.id
|
||||||
LEFT JOIN adlist ON adlist.id = antigravity.adlist_id
|
LEFT JOIN "group" ON "group".id = whitelist_by_group.group_id
|
||||||
LEFT JOIN "group" ON "group".id = adlist_by_group.group_id
|
WHERE whitelist.enabled = 1 AND (whitelist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1) AND adlist.type = 1;
|
ORDER BY whitelist.id;
|
||||||
|
|
||||||
CREATE VIEW vw_adlist AS SELECT DISTINCT address, id, type
|
CREATE TRIGGER tr_whitelist_update AFTER UPDATE ON whitelist
|
||||||
|
BEGIN
|
||||||
|
UPDATE whitelist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE domain = NEW.domain;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE VIEW vw_blacklist AS SELECT DISTINCT domain
|
||||||
|
FROM blacklist
|
||||||
|
LEFT JOIN blacklist_by_group ON blacklist_by_group.blacklist_id = blacklist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = blacklist_by_group.group_id
|
||||||
|
WHERE blacklist.enabled = 1 AND (blacklist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
ORDER BY blacklist.id;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_blacklist_update AFTER UPDATE ON blacklist
|
||||||
|
BEGIN
|
||||||
|
UPDATE blacklist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE domain = NEW.domain;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE VIEW vw_regex AS SELECT DISTINCT domain
|
||||||
|
FROM regex
|
||||||
|
LEFT JOIN regex_by_group ON regex_by_group.regex_id = regex.id
|
||||||
|
LEFT JOIN "group" ON "group".id = regex_by_group.group_id
|
||||||
|
WHERE regex.enabled = 1 AND (regex_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
ORDER BY regex.id;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_regex_update AFTER UPDATE ON regex
|
||||||
|
BEGIN
|
||||||
|
UPDATE regex SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE domain = NEW.domain;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE VIEW vw_adlist AS SELECT DISTINCT address
|
||||||
FROM adlist
|
FROM adlist
|
||||||
WHERE enabled = 1
|
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = adlist.id
|
||||||
ORDER BY 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
|
CREATE TRIGGER tr_adlist_update AFTER UPDATE ON adlist
|
||||||
BEGIN
|
BEGIN
|
||||||
INSERT INTO domainlist_by_group (domainlist_id, group_id) VALUES (NEW.id, 0);
|
UPDATE adlist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE address = NEW.address;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER tr_client_add AFTER INSERT ON client
|
|
||||||
BEGIN
|
|
||||||
INSERT INTO client_by_group (client_id, group_id) VALUES (NEW.id, 0);
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_adlist_add AFTER INSERT ON adlist
|
|
||||||
BEGIN
|
|
||||||
INSERT INTO adlist_by_group (adlist_id, group_id) VALUES (NEW.id, 0);
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_group_update AFTER UPDATE ON "group"
|
|
||||||
BEGIN
|
|
||||||
UPDATE "group" SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_group_zero AFTER DELETE ON "group"
|
|
||||||
BEGIN
|
|
||||||
INSERT OR IGNORE INTO "group" (id,enabled,name) VALUES (0,1,'Default');
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_domainlist_delete AFTER DELETE ON domainlist
|
|
||||||
BEGIN
|
|
||||||
DELETE FROM domainlist_by_group WHERE domainlist_id = OLD.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_adlist_delete AFTER DELETE ON adlist
|
|
||||||
BEGIN
|
|
||||||
DELETE FROM adlist_by_group WHERE adlist_id = OLD.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_client_delete AFTER DELETE ON client
|
|
||||||
BEGIN
|
|
||||||
DELETE FROM client_by_group WHERE client_id = OLD.id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
.timeout 30000
|
|
||||||
|
|
||||||
ATTACH DATABASE '/etc/pihole/gravity.db' AS OLD;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
|
||||||
|
|
||||||
DROP TRIGGER tr_domainlist_add;
|
|
||||||
DROP TRIGGER tr_client_add;
|
|
||||||
DROP TRIGGER tr_adlist_add;
|
|
||||||
|
|
||||||
INSERT OR REPLACE INTO "group" SELECT * FROM OLD."group";
|
|
||||||
|
|
||||||
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 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;
|
|
||||||
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_domainlist_add AFTER INSERT ON domainlist
|
|
||||||
BEGIN
|
|
||||||
INSERT INTO domainlist_by_group (domainlist_id, group_id) VALUES (NEW.id, 0);
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_client_add AFTER INSERT ON client
|
|
||||||
BEGIN
|
|
||||||
INSERT INTO client_by_group (client_id, group_id) VALUES (NEW.id, 0);
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TRIGGER tr_adlist_add AFTER INSERT ON adlist
|
|
||||||
BEGIN
|
|
||||||
INSERT INTO adlist_by_group (adlist_id, group_id) VALUES (NEW.id, 0);
|
|
||||||
END;
|
|
||||||
|
|
||||||
|
|
||||||
COMMIT;
|
|
||||||
@@ -1,32 +1,21 @@
|
|||||||
/var/log/pihole/pihole.log {
|
/var/log/pihole.log {
|
||||||
# su #
|
# su #
|
||||||
daily
|
daily
|
||||||
copytruncate
|
copytruncate
|
||||||
rotate 5
|
rotate 5
|
||||||
compress
|
compress
|
||||||
delaycompress
|
delaycompress
|
||||||
notifempty
|
notifempty
|
||||||
nomail
|
nomail
|
||||||
}
|
}
|
||||||
|
|
||||||
/var/log/pihole/FTL.log {
|
/var/log/pihole-FTL.log {
|
||||||
# su #
|
# su #
|
||||||
weekly
|
weekly
|
||||||
copytruncate
|
copytruncate
|
||||||
rotate 3
|
rotate 3
|
||||||
compress
|
compress
|
||||||
delaycompress
|
delaycompress
|
||||||
notifempty
|
notifempty
|
||||||
nomail
|
nomail
|
||||||
}
|
|
||||||
|
|
||||||
/var/log/pihole/webserver.log {
|
|
||||||
# su #
|
|
||||||
weekly
|
|
||||||
copytruncate
|
|
||||||
rotate 3
|
|
||||||
compress
|
|
||||||
delaycompress
|
|
||||||
notifempty
|
|
||||||
nomail
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# Source utils.sh for getFTLConfigValue()
|
|
||||||
PI_HOLE_SCRIPT_DIR='/opt/pihole'
|
|
||||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
|
||||||
# shellcheck source="./advanced/Scripts/utils.sh"
|
|
||||||
. "${utilsfile}"
|
|
||||||
|
|
||||||
# Get file paths
|
|
||||||
FTL_PID_FILE="$(getFTLConfigValue files.pid)"
|
|
||||||
|
|
||||||
# Cleanup
|
|
||||||
rm -f /run/pihole/FTL.sock /dev/shm/FTL-* "${FTL_PID_FILE}"
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# Source utils.sh for getFTLConfigValue()
|
|
||||||
PI_HOLE_SCRIPT_DIR='/opt/pihole'
|
|
||||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
|
||||||
# shellcheck source="./advanced/Scripts/utils.sh"
|
|
||||||
. "${utilsfile}"
|
|
||||||
|
|
||||||
# Get file paths
|
|
||||||
FTL_PID_FILE="$(getFTLConfigValue files.pid)"
|
|
||||||
FTL_LOG_FILE="$(getFTLConfigValue files.log.ftl)"
|
|
||||||
PIHOLE_LOG_FILE="$(getFTLConfigValue files.log.dnsmasq)"
|
|
||||||
WEBSERVER_LOG_FILE="$(getFTLConfigValue files.log.webserver)"
|
|
||||||
FTL_PID_FILE="${FTL_PID_FILE:-/run/pihole-FTL.pid}"
|
|
||||||
FTL_LOG_FILE="${FTL_LOG_FILE:-/var/log/pihole/FTL.log}"
|
|
||||||
PIHOLE_LOG_FILE="${PIHOLE_LOG_FILE:-/var/log/pihole/pihole.log}"
|
|
||||||
WEBSERVER_LOG_FILE="${WEBSERVER_LOG_FILE:-/var/log/pihole/webserver.log}"
|
|
||||||
|
|
||||||
# Ensure that permissions are set so that pihole-FTL can edit all necessary files
|
|
||||||
mkdir -p /var/log/pihole
|
|
||||||
chown -R pihole:pihole /etc/pihole/ /var/log/pihole/
|
|
||||||
|
|
||||||
# allow all users read version file (and use pihole -v)
|
|
||||||
touch /etc/pihole/versions
|
|
||||||
chmod 0644 /etc/pihole/versions
|
|
||||||
|
|
||||||
# allow pihole to access subdirs in /etc/pihole (sets execution bit on dirs)
|
|
||||||
find /etc/pihole/ /var/log/pihole/ -type d -exec chmod 0755 {} +
|
|
||||||
# Set all files (except TLS-related ones) to u+rw g+r
|
|
||||||
find /etc/pihole/ /var/log/pihole/ -type f ! \( -name '*.pem' -o -name '*.crt' \) -exec chmod 0640 {} +
|
|
||||||
# Set TLS-related files to a more restrictive u+rw *only* (they may contain private keys)
|
|
||||||
find /etc/pihole/ -type f \( -name '*.pem' -o -name '*.crt' \) -exec chmod 0600 {} +
|
|
||||||
|
|
||||||
# Logrotate config file need to be owned by root
|
|
||||||
chown root:root /etc/pihole/logrotate
|
|
||||||
|
|
||||||
# Touch files to ensure they exist (create if non-existing, preserve if existing)
|
|
||||||
[ -f "${FTL_PID_FILE}" ] || install -D -m 644 -o pihole -g pihole /dev/null "${FTL_PID_FILE}"
|
|
||||||
[ -f "${FTL_LOG_FILE}" ] || install -m 640 -o pihole -g pihole /dev/null "${FTL_LOG_FILE}"
|
|
||||||
[ -f "${PIHOLE_LOG_FILE}" ] || install -m 640 -o pihole -g pihole /dev/null "${PIHOLE_LOG_FILE}"
|
|
||||||
[ -f "${WEBSERVER_LOG_FILE}" ] || install -m 640 -o pihole -g pihole /dev/null "${WEBSERVER_LOG_FILE}"
|
|
||||||
[ -f /etc/pihole/dhcp.leases ] || install -m 644 -o pihole -g pihole /dev/null /etc/pihole/dhcp.leases
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#!/sbin/openrc-run
|
|
||||||
# shellcheck shell=sh disable=SC2034
|
|
||||||
|
|
||||||
: "${PI_HOLE_SCRIPT_DIR:=/opt/pihole}"
|
|
||||||
|
|
||||||
command="/usr/bin/pihole-FTL"
|
|
||||||
command_user="pihole:pihole"
|
|
||||||
supervisor=supervise-daemon
|
|
||||||
command_args_foreground="-f"
|
|
||||||
command_background=true
|
|
||||||
pidfile="/run/${RC_SVCNAME}_openrc.pid"
|
|
||||||
extra_started_commands="reload"
|
|
||||||
|
|
||||||
respawn_max=5
|
|
||||||
respawn_period=60
|
|
||||||
capabilities="^CAP_NET_BIND_SERVICE,^CAP_NET_RAW,^CAP_NET_ADMIN,^CAP_SYS_NICE,^CAP_IPC_LOCK,^CAP_CHOWN,^CAP_SYS_TIME"
|
|
||||||
|
|
||||||
depend() {
|
|
||||||
want net
|
|
||||||
provide dns
|
|
||||||
}
|
|
||||||
|
|
||||||
checkconfig() {
|
|
||||||
$command -f test
|
|
||||||
}
|
|
||||||
|
|
||||||
start_pre() {
|
|
||||||
sh "${PI_HOLE_SCRIPT_DIR}/pihole-FTL-prestart.sh"
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_post() {
|
|
||||||
sh "${PI_HOLE_SCRIPT_DIR}/pihole-FTL-poststop.sh"
|
|
||||||
}
|
|
||||||
|
|
||||||
reload() {
|
|
||||||
checkconfig || return $?
|
|
||||||
ebegin "Reloading ${RC_SVCNAME}"
|
|
||||||
start-stop-daemon --signal HUP --pidfile "${pidfile}"
|
|
||||||
eend $?
|
|
||||||
}
|
|
||||||
@@ -1,31 +1,30 @@
|
|||||||
#!/usr/bin/env sh
|
#!/bin/bash
|
||||||
### BEGIN INIT INFO
|
### BEGIN INIT INFO
|
||||||
# Provides: pihole-FTL
|
# Provides: pihole-FTL
|
||||||
# Required-Start: $remote_fs $syslog $network
|
# Required-Start: $remote_fs $syslog
|
||||||
# Required-Stop: $remote_fs $syslog $network
|
# Required-Stop: $remote_fs $syslog
|
||||||
# Default-Start: 2 3 4 5
|
# Default-Start: 2 3 4 5
|
||||||
# Default-Stop: 0 1 6
|
# Default-Stop: 0 1 6
|
||||||
# Short-Description: pihole-FTL daemon
|
# Short-Description: pihole-FTL daemon
|
||||||
# Description: Enable service provided by pihole-FTL daemon
|
# Description: Enable service provided by pihole-FTL daemon
|
||||||
### END INIT INFO
|
### END INIT INFO
|
||||||
|
|
||||||
# Source utils.sh for getFTLConfigValue(), getFTLPID()
|
FTLUSER=pihole
|
||||||
PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
PIDFILE=/var/run/pihole-FTL.pid
|
||||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
|
||||||
# shellcheck source="./advanced/Scripts/utils.sh"
|
|
||||||
. "${utilsfile}"
|
|
||||||
|
|
||||||
|
get_pid() {
|
||||||
|
# First, try to obtain PID from PIDFILE
|
||||||
|
if [ -s "${PIDFILE}" ]; then
|
||||||
|
cat "${PIDFILE}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
is_running() {
|
# If the PIDFILE is empty or not available, obtain the PID using pidof
|
||||||
if [ -d "/proc/${FTL_PID}" ]; then
|
pidof "pihole-FTL" | awk '{print $(NF)}'
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup() {
|
is_running() {
|
||||||
# Run post-stop script, which does cleanup among runtime files
|
ps "$(get_pid)" > /dev/null 2>&1
|
||||||
sh "${PI_HOLE_SCRIPT_DIR}/pihole-FTL-poststop.sh"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -34,20 +33,27 @@ start() {
|
|||||||
if is_running; then
|
if is_running; then
|
||||||
echo "pihole-FTL is already running"
|
echo "pihole-FTL is already running"
|
||||||
else
|
else
|
||||||
# Run pre-start script, which pre-creates all expected files with correct permissions
|
# Touch files to ensure they exist (create if non-existing, preserve if existing)
|
||||||
sh "${PI_HOLE_SCRIPT_DIR}/pihole-FTL-prestart.sh"
|
touch /var/log/pihole-FTL.log /var/log/pihole.log
|
||||||
|
touch /run/pihole-FTL.pid /run/pihole-FTL.port
|
||||||
if setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_NICE,CAP_IPC_LOCK,CAP_CHOWN,CAP_SYS_TIME+eip "/usr/bin/pihole-FTL"; then
|
touch /etc/pihole/dhcp.leases
|
||||||
su -s /bin/sh -c "/usr/bin/pihole-FTL" pihole
|
mkdir -p /var/run/pihole
|
||||||
|
mkdir -p /var/log/pihole
|
||||||
|
chown pihole:pihole /var/run/pihole /var/log/pihole
|
||||||
|
# Remove possible leftovers from previous pihole-FTL processes
|
||||||
|
rm -f /dev/shm/FTL-* 2> /dev/null
|
||||||
|
rm /var/run/pihole/FTL.sock 2> /dev/null
|
||||||
|
# Ensure that permissions are set so that pihole-FTL can edit all necessary files
|
||||||
|
chown pihole:pihole /run/pihole-FTL.pid /run/pihole-FTL.port
|
||||||
|
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
|
||||||
|
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.piholeFTL
|
||||||
|
if setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN+eip "$(which pihole-FTL)"; then
|
||||||
|
su -s /bin/sh -c "/usr/bin/pihole-FTL" "$FTLUSER"
|
||||||
else
|
else
|
||||||
echo "Warning: Starting pihole-FTL as root because setting capabilities is not supported on this system"
|
echo "Warning: Starting pihole-FTL as root because setting capabilities is not supported on this system"
|
||||||
/usr/bin/pihole-FTL
|
pihole-FTL
|
||||||
fi
|
|
||||||
rc=$?
|
|
||||||
# Cleanup if startup failed
|
|
||||||
if [ "${rc}" != 0 ]; then
|
|
||||||
cleanup
|
|
||||||
exit $rc
|
|
||||||
fi
|
fi
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
@@ -56,30 +62,28 @@ start() {
|
|||||||
# Stop the service
|
# Stop the service
|
||||||
stop() {
|
stop() {
|
||||||
if is_running; then
|
if is_running; then
|
||||||
kill "${FTL_PID}"
|
/sbin/resolvconf -d lo.piholeFTL
|
||||||
# Give FTL 120 seconds to gracefully stop
|
kill "$(get_pid)"
|
||||||
i=1
|
for i in {1..5}; do
|
||||||
while [ "${i}" -le 120 ]; do
|
|
||||||
if ! is_running; then
|
if ! is_running; then
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf "."
|
echo -n "."
|
||||||
sleep 1
|
sleep 1
|
||||||
i=$((i + 1))
|
|
||||||
done
|
done
|
||||||
echo
|
echo
|
||||||
|
|
||||||
if is_running; then
|
if is_running; then
|
||||||
echo "Not stopped; may still be shutting down or shutdown may have failed, killing now"
|
echo "Not stopped; may still be shutting down or shutdown may have failed, killing now"
|
||||||
kill -9 "${FTL_PID}"
|
kill -9 "$(get_pid)"
|
||||||
|
exit 1
|
||||||
else
|
else
|
||||||
echo "Stopped"
|
echo "Stopped"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Not running"
|
echo "Not running"
|
||||||
fi
|
fi
|
||||||
cleanup
|
|
||||||
echo
|
echo
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,16 +100,6 @@ status() {
|
|||||||
|
|
||||||
|
|
||||||
### main logic ###
|
### main logic ###
|
||||||
|
|
||||||
# catch sudden termination
|
|
||||||
trap 'cleanup; exit 1' INT HUP TERM ABRT
|
|
||||||
|
|
||||||
# Get FTL's PID file path
|
|
||||||
FTL_PID_FILE="$(getFTLConfigValue files.pid)"
|
|
||||||
|
|
||||||
# Get FTL's current PID
|
|
||||||
FTL_PID="$(getFTLPID "${FTL_PID_FILE}")"
|
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
stop)
|
stop)
|
||||||
stop
|
stop
|
||||||
@@ -118,7 +112,7 @@ case "$1" in
|
|||||||
start
|
start
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 {start|stop|restart|reload|status}"
|
echo $"Usage: $0 {start|stop|restart|reload|status}"
|
||||||
exit 1
|
exit 1
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Pi-hole FTL
|
|
||||||
# This unit is supposed to indicate when network functionality is available, but it is only
|
|
||||||
# very weakly defined what that is supposed to mean, with one exception: at shutdown, a unit
|
|
||||||
# that is ordered after network-online.target will be stopped before the network
|
|
||||||
Wants=network-online.target
|
|
||||||
After=network-online.target
|
|
||||||
# A target that should be used as synchronization point for all host/network name service lookups.
|
|
||||||
# All services for which the availability of full host/network name resolution is essential should
|
|
||||||
# be ordered after this target, but not pull it in.
|
|
||||||
Wants=nss-lookup.target
|
|
||||||
Before=nss-lookup.target
|
|
||||||
|
|
||||||
# Limit (re)start loop to 5 within 1 minute
|
|
||||||
StartLimitBurst=5
|
|
||||||
StartLimitIntervalSec=60s
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
User=pihole
|
|
||||||
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN CAP_SYS_NICE CAP_IPC_LOCK CAP_CHOWN CAP_SYS_TIME
|
|
||||||
|
|
||||||
# Run prestart with elevated permissions
|
|
||||||
ExecStartPre=+/opt/pihole/pihole-FTL-prestart.sh
|
|
||||||
ExecStart=/usr/bin/pihole-FTL -f
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=5s
|
|
||||||
ExecReload=/bin/kill -HUP $MAINPID
|
|
||||||
ExecStopPost=+/opt/pihole/pihole-FTL-poststop.sh
|
|
||||||
|
|
||||||
# Use graceful shutdown with a reasonable timeout
|
|
||||||
TimeoutStopSec=120s
|
|
||||||
|
|
||||||
# Make /usr, /boot, /etc and possibly some more folders read-only...
|
|
||||||
ProtectSystem=full
|
|
||||||
# ... except /etc/pihole
|
|
||||||
# This merely retains r/w access rights, it does not add any new.
|
|
||||||
# Must still be writable on the host!
|
|
||||||
ReadWriteDirectories=/etc/pihole
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
# This file is under source-control of the Pi-hole installation and update
|
# This file is under source-control of the Pi-hole installation and update
|
||||||
# scripts, any changes made to this file will be overwritten when the software
|
# scripts, any changes made to this file will be overwritten when the softare
|
||||||
# is updated or re-installed. Please make any changes to the appropriate crontab
|
# is updated or re-installed. Please make any changes to the appropriate crontab
|
||||||
# or other cron file snippets.
|
# or other cron file snippets.
|
||||||
|
|
||||||
@@ -18,16 +18,19 @@
|
|||||||
# early morning. Download any updates from the adlists
|
# early morning. Download any updates from the adlists
|
||||||
# Squash output to log, then splat the log to stdout on error to allow for
|
# Squash output to log, then splat the log to stdout on error to allow for
|
||||||
# standard crontab job error handling.
|
# standard crontab job error handling.
|
||||||
59 1 * * 7 root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updateGravity >/var/log/pihole/pihole_updateGravity.log || cat /var/log/pihole/pihole_updateGravity.log
|
59 1 * * 7 root PATH="$PATH:/usr/local/bin/" pihole updateGravity >/var/log/pihole_updateGravity.log || cat /var/log/pihole_updateGravity.log
|
||||||
|
|
||||||
# Pi-hole: Flush the log daily at 00:00
|
# Pi-hole: Flush the log daily at 00:00
|
||||||
# The flush script will use logrotate if available
|
# The flush script will use logrotate if available
|
||||||
# parameter "once": logrotate only once (default is twice)
|
# parameter "once": logrotate only once (default is twice)
|
||||||
# parameter "quiet": don't print messages
|
# parameter "quiet": don't print messages
|
||||||
00 00 * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole logrotate quiet
|
00 00 * * * root PATH="$PATH:/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 remote and local version every 24 hours
|
# Pi-hole: Grab local version and branch every 10 minutes
|
||||||
59 17 * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker
|
*/10 * * * * root PATH="$PATH:/usr/local/bin/" pihole updatechecker local
|
||||||
@reboot root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker reboot
|
|
||||||
|
# Pi-hole: Grab remote version every 24 hours
|
||||||
|
59 17 * * * root PATH="$PATH:/usr/local/bin/" pihole updatechecker remote
|
||||||
|
@reboot root PATH="$PATH:/usr/local/bin/" pihole updatechecker remote reboot
|
||||||
|
|||||||
9
advanced/Templates/pihole.sudo
Normal file
9
advanced/Templates/pihole.sudo
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Allows the WebUI to use Pi-hole commands
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
#
|
||||||
79
advanced/bash-completion/pihole
Normal file
79
advanced/bash-completion/pihole
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
_pihole() {
|
||||||
|
local cur prev opts opts_admin opts_checkout opts_chronometer opts_debug opts_interface opts_logging opts_privacy opts_query opts_update opts_version
|
||||||
|
COMPREPLY=()
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
|
prev2="${COMP_WORDS[COMP_CWORD-2]}"
|
||||||
|
|
||||||
|
case "${prev}" in
|
||||||
|
"pihole")
|
||||||
|
opts="admin blacklist checkout chronometer debug disable enable flush help logging query reconfigure regex restartdns status tail uninstall updateGravity updatePihole version wildcard whitelist arpflush"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"whitelist"|"blacklist"|"wildcard"|"regex")
|
||||||
|
opts_lists="\--delmode \--noreload \--quiet \--list \--nuke"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_lists}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"admin")
|
||||||
|
opts_admin="celsius email fahrenheit hostrecord interface kelvin password privacylevel"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_admin}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"checkout")
|
||||||
|
opts_checkout="core ftl web master dev"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_checkout}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"chronometer")
|
||||||
|
opts_chronometer="\--exit \--json \--refresh"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_chronometer}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"debug")
|
||||||
|
opts_debug="-a"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_debug}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"logging")
|
||||||
|
opts_logging="on off 'off noflush'"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_logging}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"query")
|
||||||
|
opts_query="-adlist -all -exact"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_query}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"updatePihole"|"-up")
|
||||||
|
opts_update="--check-only"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_update}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"version")
|
||||||
|
opts_version="\--admin \--current \--ftl \--hash \--latest \--pihole"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_version}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"interface")
|
||||||
|
if ( [[ "$prev2" == "admin" ]] || [[ "$prev2" == "-a" ]] ); then
|
||||||
|
opts_interface="$(cat /proc/net/dev | cut -d: -s -f1)"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_interface}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"privacylevel")
|
||||||
|
if ( [[ "$prev2" == "admin" ]] || [[ "$prev2" == "-a" ]] ); then
|
||||||
|
opts_privacy="0 1 2 3 4"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_privacy}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"core"|"admin"|"ftl")
|
||||||
|
if [[ "$prev2" == "checkout" ]]; then
|
||||||
|
opts_checkout="master dev"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_checkout}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
complete -F _pihole pihole
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Bash completion script for pihole-FTL
|
|
||||||
#
|
|
||||||
# This completion script provides tab completion for pihole-FTL CLI flags and commands.
|
|
||||||
# It uses the `pihole-FTL --complete` command to generate the completion options.
|
|
||||||
_complete_FTL() { mapfile -t COMPREPLY < <(pihole-FTL --complete "${COMP_WORDS[@]}"); }
|
|
||||||
|
|
||||||
complete -F _complete_FTL pihole-FTL
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Bash completion script for pihole
|
|
||||||
#
|
|
||||||
_pihole() {
|
|
||||||
local cur prev prev2 opts opts_lists opts_checkout opts_debug opts_logging opts_query opts_update opts_networkflush
|
|
||||||
COMPREPLY=()
|
|
||||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
|
||||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
|
||||||
prev2="${COMP_WORDS[COMP_CWORD-2]}"
|
|
||||||
|
|
||||||
case "${prev}" in
|
|
||||||
"pihole")
|
|
||||||
opts="allow allow-regex allow-wild deny checkout debug disable enable flush help logging query repair regex reloaddns reloadlists setpassword status tail uninstall updateGravity updatePihole version wildcard networkflush api"
|
|
||||||
mapfile -t COMPREPLY < <(compgen -W "${opts}" -- "${cur}")
|
|
||||||
;;
|
|
||||||
"allow"|"deny"|"wildcard"|"regex"|"allow-regex"|"allow-wild")
|
|
||||||
opts_lists="\not \--delmode \--quiet \--list \--help"
|
|
||||||
mapfile -t COMPREPLY < <(compgen -W "${opts_lists}" -- "${cur}")
|
|
||||||
;;
|
|
||||||
"checkout")
|
|
||||||
opts_checkout="core ftl web master dev"
|
|
||||||
mapfile -t COMPREPLY < <(compgen -W "${opts_checkout}" -- "${cur}")
|
|
||||||
;;
|
|
||||||
"debug")
|
|
||||||
opts_debug="-a"
|
|
||||||
mapfile -t COMPREPLY < <(compgen -W "${opts_debug}" -- "${cur}")
|
|
||||||
;;
|
|
||||||
"logging")
|
|
||||||
opts_logging="on off 'off noflush'"
|
|
||||||
mapfile -t COMPREPLY < <(compgen -W "${opts_logging}" -- "${cur}")
|
|
||||||
;;
|
|
||||||
"query")
|
|
||||||
opts_query="--partial --all"
|
|
||||||
mapfile -t COMPREPLY < <(compgen -W "${opts_query}" -- "${cur}")
|
|
||||||
;;
|
|
||||||
"updatePihole"|"-up")
|
|
||||||
opts_update="--check-only"
|
|
||||||
mapfile -t COMPREPLY < <(compgen -W "${opts_update}" -- "${cur}")
|
|
||||||
;;
|
|
||||||
"networkflush")
|
|
||||||
opts_networkflush="--arp"
|
|
||||||
mapfile -t COMPREPLY < <(compgen -W "${opts_networkflush}" -- "${cur}")
|
|
||||||
;;
|
|
||||||
"core"|"web"|"ftl")
|
|
||||||
if [[ "$prev2" == "checkout" ]]; then
|
|
||||||
opts_checkout="master development"
|
|
||||||
mapfile -t COMPREPLY < <(compgen -W "${opts_checkout}" -- "${cur}")
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
complete -F _pihole pihole
|
|
||||||
383
advanced/blockingpage.css
Normal file
383
advanced/blockingpage.css
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
/* Pi-hole: A black hole for Internet advertisements
|
||||||
|
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
* Network-wide ad blocking via your own hardware.
|
||||||
|
*
|
||||||
|
* This file is copyright under the latest version of the EUPL.
|
||||||
|
* Please see LICENSE file for your rights under this license. */
|
||||||
|
|
||||||
|
/* Text Customisation Options ======> */
|
||||||
|
.title:before { content: "Website Blocked"; }
|
||||||
|
.altBtn:before { content: "Why am I here?"; }
|
||||||
|
.linkPH:before { content: "About Pi-hole"; }
|
||||||
|
.linkEmail:before { content: "Contact Admin"; }
|
||||||
|
|
||||||
|
#bpOutput.add:before { content: "Info"; }
|
||||||
|
#bpOutput.add:after { content: "The domain is being whitelisted..."; }
|
||||||
|
#bpOutput.error:before, .unhandled:before { content: "Error"; }
|
||||||
|
#bpOutput.unhandled:after { content: "An unhandled exception occured. This may happen when your browser is unable to load jQuery, or when the webserver is denying access to the Pi-hole API."; }
|
||||||
|
#bpOutput.success:before { content: "Success"; }
|
||||||
|
#bpOutput.success:after { content: "Website has been whitelisted! You may need to flush your DNS cache"; }
|
||||||
|
|
||||||
|
.recentwl:before { content: "This site has been whitelisted. Please flush your DNS cache and/or restart your browser."; }
|
||||||
|
.unknown:before { content: "This website is not found in any of Pi-hole's blacklists. The reason you have arrived here is unknown."; }
|
||||||
|
.cname:before { content: "This site is an alias for "; } /* <a href="http://cname.com">cname.com</a> */
|
||||||
|
.cname:after { content: ", which may be blocked by Pi-hole."; }
|
||||||
|
|
||||||
|
.blacklist:before { content: "Manually Blacklisted"; }
|
||||||
|
.wildcard:before { content: "Manually Blacklisted by Wildcard"; }
|
||||||
|
.noblock:before { content: "Not found on any Blacklist"; }
|
||||||
|
|
||||||
|
#bpBlock:before { content: "Access to the following website has been denied:"; }
|
||||||
|
#bpFlag:before { content: "This is primarily due to being flagged as:"; }
|
||||||
|
|
||||||
|
#bpHelpTxt:before { content: "If you have an ongoing use for this website, please "; }
|
||||||
|
#bpHelpTxt a:before, #bpHelpTxt span:before { content: "ask the administrator"; }
|
||||||
|
#bpHelpTxt:after{ content: " of the Pi-hole on this network to have it whitelisted"; }
|
||||||
|
|
||||||
|
#bpBack:before { content: "Back to safety"; }
|
||||||
|
#bpInfo:before { content: "Technical Info"; }
|
||||||
|
#bpFoundIn:before { content: "This site is found in "; }
|
||||||
|
#bpFoundIn span:after { content: " of "; }
|
||||||
|
#bpFoundIn:after { content: " lists:"; }
|
||||||
|
#bpWhitelist:before { content: "Whitelist"; }
|
||||||
|
|
||||||
|
footer span:before { content: "Page generated on "; }
|
||||||
|
|
||||||
|
/* Hide whitelisting form entirely */
|
||||||
|
/* #bpWLButtons { display: none; } */
|
||||||
|
/* Text Customisation Options <=============================== */
|
||||||
|
|
||||||
|
/* http://necolas.github.io/normalize.css ======> */
|
||||||
|
html { font-family: sans-serif; line-height: 1.15; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; }
|
||||||
|
body { margin: 0; }
|
||||||
|
article, aside, footer, header, nav, section { display: block; }
|
||||||
|
h1 { font-size: 2em; margin: 0.67em 0; }
|
||||||
|
figcaption, figure, main { display: block; }
|
||||||
|
figure { margin: 1em 40px; }
|
||||||
|
hr { box-sizing: content-box; height: 0; overflow: visible; }
|
||||||
|
pre { font-family: monospace, monospace; font-size: 1em; }
|
||||||
|
a { background-color: transparent; -webkit-text-decoration-skip: objects; }
|
||||||
|
a:active, a:hover { outline-width: 0; }
|
||||||
|
abbr[title] { border-bottom: none; text-decoration: underline; text-decoration: underline dotted; }
|
||||||
|
b, strong { font-weight: inherit; }
|
||||||
|
b, strong { font-weight: bolder; }
|
||||||
|
code, kbd, samp { font-family: monospace, monospace; font-size: 1em; }
|
||||||
|
dfn { font-style: italic; }
|
||||||
|
mark { background-color: #ff0; color: #000; }
|
||||||
|
small { font-size: 80%; }
|
||||||
|
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
|
||||||
|
sub { bottom: -0.25em; }
|
||||||
|
sup { top: -0.5em; }
|
||||||
|
audio, video { display: inline-block; }
|
||||||
|
audio:not([controls]) { display: none; height: 0; }
|
||||||
|
img { border-style: none; }
|
||||||
|
svg:not(:root) { overflow: hidden; }
|
||||||
|
button, input, optgroup, select, textarea { font-family: sans-serif; font-size: 100%; line-height: 1.15; margin: 0; }
|
||||||
|
button, input { overflow: visible; }
|
||||||
|
button, select { text-transform: none; }
|
||||||
|
button, html [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; }
|
||||||
|
button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; }
|
||||||
|
button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; }
|
||||||
|
fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }
|
||||||
|
legend { box-sizing: border-box; color: inherit; display: table; max-width: 100%; padding: 0; white-space: normal; }
|
||||||
|
progress { display: inline-block; vertical-align: baseline; }
|
||||||
|
textarea { overflow: auto; }
|
||||||
|
[type="checkbox"], [type="radio"] { box-sizing: border-box; padding: 0; }
|
||||||
|
[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; }
|
||||||
|
[type="search"] { -webkit-appearance: textfield; outline-offset: -2px; }
|
||||||
|
[type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
|
||||||
|
::-webkit-file-upload-button { -webkit-appearance: button; font: inherit; }
|
||||||
|
details, menu { display: block; }
|
||||||
|
summary { display: list-item; }
|
||||||
|
canvas { display: inline-block; }
|
||||||
|
template { display: none; }
|
||||||
|
[hidden] { display: none; }
|
||||||
|
/* Normalize.css <=============================== */
|
||||||
|
|
||||||
|
html { font-size: 62.5%; }
|
||||||
|
|
||||||
|
a { color: #3c8dbc; text-decoration: none; }
|
||||||
|
a:hover { color: #72afda; text-decoration: underline; }
|
||||||
|
b { color: rgb(68,68,68); }
|
||||||
|
p { margin: 0; }
|
||||||
|
|
||||||
|
label, .buttons a {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
label, .buttons *:not([disabled]) { cursor: pointer; }
|
||||||
|
|
||||||
|
/* Touch device dark tap highlight */
|
||||||
|
header h1 a, label, .buttons * { -webkit-tap-highlight-color: transparent; }
|
||||||
|
|
||||||
|
/* Webkit Focus Glow */
|
||||||
|
textarea, input, button { outline: none; }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Source Sans Pro";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local("Source Sans Pro"), local("SourceSansPro-Regular"), url("/admin/style/vendor/SourceSansPro/SourceSansPro-Regular.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Source Sans Pro";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local("Source Sans Pro Bold"), local("SourceSansPro-Bold"), url("/admin/style/vendor/SourceSansPro/SourceSansPro-Bold.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #dbdbdb url("/admin/img/boxed-bg.jpg") repeat fixed;
|
||||||
|
color: #333;
|
||||||
|
font: 1.4rem "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
line-height: 2.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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; }
|
||||||
|
#splashpage img { margin: 5px; width: 256px; }
|
||||||
|
#splashpage b { color: inherit; }
|
||||||
|
|
||||||
|
#bpWrapper {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 1250px;
|
||||||
|
box-shadow: 0 0 8px rgba(0,0,0,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background: #3c8dbc;
|
||||||
|
display: table;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1, header h1 a, header .spc, header #bpAlt label {
|
||||||
|
display: table-cell;
|
||||||
|
color: #fff;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 50px; /* Must match #bpAbout top value */
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a {
|
||||||
|
background-color: rgba(0,0,0,0.1);
|
||||||
|
font-family: "Helvetica Neue", Helvetica, Arial ,sans-serif;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: normal;
|
||||||
|
min-width: 230px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a:hover, header #bpAlt:hover { background-color: rgba(0,0,0,0.12); color: inherit; text-decoration: none; }
|
||||||
|
|
||||||
|
header .spc { width: 100%; }
|
||||||
|
|
||||||
|
header #bpAlt label {
|
||||||
|
background: url("/admin/img/logo.svg") no-repeat center left 15px;
|
||||||
|
background-size: 15px 23px;
|
||||||
|
padding: 0 15px;
|
||||||
|
text-indent: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type=checkbox][id$="Toggle"] { display: none; }
|
||||||
|
[type=checkbox][id$="Toggle"]:checked ~ #bpAbout,
|
||||||
|
[type=checkbox][id$="Toggle"]:checked ~ #bpMoreInfo {
|
||||||
|
display: block; }
|
||||||
|
|
||||||
|
/* Click anywhere else on screen to hide #bpAbout */
|
||||||
|
#bpAboutToggle:checked {
|
||||||
|
display: block;
|
||||||
|
height: 300px; /* VH Fallback */
|
||||||
|
height: 100vh;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpAbout {
|
||||||
|
background: #3c8dbc;
|
||||||
|
border-bottom-left-radius: 5px;
|
||||||
|
border: 1px solid #FFF;
|
||||||
|
border-right-width: 0;
|
||||||
|
box-shadow: -1px 1px 1px rgba(0,0,0,0.12);
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: none;
|
||||||
|
font-size: 1.7rem;
|
||||||
|
top: 50px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
width: 280px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aboutPH {
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: rgba(255,255,255,0.8);
|
||||||
|
display: block;
|
||||||
|
padding: 10px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aboutImg {
|
||||||
|
background: url("/admin/img/logo.svg") no-repeat center;
|
||||||
|
background-size: 90px 90px;
|
||||||
|
height: 90px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2px;
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aboutPH p { margin: 10px 0; }
|
||||||
|
.aboutPH small { display: block; font-size: 1.2rem; }
|
||||||
|
|
||||||
|
.aboutLink {
|
||||||
|
background: #fff;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
display: table;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aboutLink a {
|
||||||
|
display: table-cell;
|
||||||
|
padding: 14px;
|
||||||
|
min-width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
background: #ecf0f5;
|
||||||
|
font-size: 1.65rem;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpOutput {
|
||||||
|
background: #00c0ef;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid rgba(0,0,0,0.1);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpOutput:before {
|
||||||
|
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='14' viewBox='0 0 7 14'%3E%3Cpath fill='%23fff' d='M6,11a1.371,1.371,0,0,1,1,1v1a1.371,1.371,0,0,1-1,1H1a1.371,1.371,0,0,1-1-1V12a1.371,1.371,0,0,1,1-1H2V8H1A1.371,1.371,0,0,1,0,7V6A1.371,1.371,0,0,1,1,5H4A1.371,1.371,0,0,1,5,6v5H6ZM3.5,0A1.5,1.5,0,1,1,2,1.5,1.5,1.5,0,0,1,3.5,0Z'/%3E%3C/svg%3E") no-repeat center left;
|
||||||
|
display: block;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
text-indent: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpOutput.hidden { display: none; }
|
||||||
|
#bpOutput.success { background: #00a65a; }
|
||||||
|
#bpOutput.error { background: #dd4b39; }
|
||||||
|
|
||||||
|
.blockMsg, .flagMsg {
|
||||||
|
font: bold 1.8rem Consolas, Courier, monospace;
|
||||||
|
padding: 5px 10px 10px 10px;
|
||||||
|
text-indent: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpHelpTxt { padding-bottom: 10px; }
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
border-spacing: 5px 0;
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons * {
|
||||||
|
-moz-appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid rgba(0,0,0,0.1);
|
||||||
|
box-sizing: content-box;
|
||||||
|
display: table-cell;
|
||||||
|
font-size: 1.65rem;
|
||||||
|
margin-right: 5px;
|
||||||
|
min-height: 20px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: top;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons a:hover { text-decoration: none; }
|
||||||
|
|
||||||
|
/* Button hover dark overlay */
|
||||||
|
.buttons *:not(input):not([disabled]):hover {
|
||||||
|
background-image: linear-gradient(to bottom, rgba(0,0,0,0.1), rgba(0,0,0,0.1));
|
||||||
|
color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button active shadow inset */
|
||||||
|
.buttons *:not([disabled]):not(input):active {
|
||||||
|
box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input border colour */
|
||||||
|
.buttons *:not([disabled]):hover, .buttons input:focus {
|
||||||
|
border-color: rgba(0,0,0,0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpButtons * { width: 50%; color: #FFF; }
|
||||||
|
#bpBack { background-color: #00a65a; }
|
||||||
|
#bpInfo { background-color: #3c8dbc; }
|
||||||
|
#bpWhitelist { background-color: #dd4b39; }
|
||||||
|
|
||||||
|
#blockpage .buttons [type=password][disabled] { color: rgba(0,0,0,1); }
|
||||||
|
#blockpage .buttons [disabled] { color: rgba(0,0,0,0.55); background-color: #e3e3e3; }
|
||||||
|
#blockpage .buttons [type=password]:-ms-input-placeholder { color: rgba(51,51,51,0.8); }
|
||||||
|
|
||||||
|
input[type=password] { font-size: 1.5rem; }
|
||||||
|
|
||||||
|
@keyframes slidein { from { max-height: 0; opacity: 0; } to { max-height: 300px; opacity: 1; } }
|
||||||
|
#bpMoreToggle:checked ~ #bpMoreInfo { display: block; margin-top: 8px; animation: slidein 0.05s linear; }
|
||||||
|
#bpMoreInfo { display: none; margin-top: 10px; }
|
||||||
|
|
||||||
|
#bpQueryOutput {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 1.65rem;
|
||||||
|
margin: 5px 0 0 0;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0 5px;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpQueryOutput span { margin-right: 4px; }
|
||||||
|
|
||||||
|
#bpWLButtons { width: auto; margin-top: 10px; }
|
||||||
|
#bpWLButtons * { display: inline-block; }
|
||||||
|
#bpWLDomain { display: none; }
|
||||||
|
#bpWLPassword { width: 160px; }
|
||||||
|
#bpWhitelist { color: #fff; }
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background: #fff;
|
||||||
|
border-top: 1px solid #d2d6de;
|
||||||
|
color: #444;
|
||||||
|
font: 1.2rem Consolas, Courier, monospace;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 1251px) {
|
||||||
|
#bpWrapper, footer { border-radius: 0 0 5px 5px; }
|
||||||
|
#bpAbout { border-right-width: 1px; }
|
||||||
|
}
|
||||||
1
advanced/cmdline.txt
Normal file
1
advanced/cmdline.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait fbcon=map:10 fbcon=font:VGA8x8 consoleblank=0
|
||||||
17
advanced/console-setup
Normal file
17
advanced/console-setup
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# CONFIGURATION FILE FOR SETUPCON
|
||||||
|
|
||||||
|
# Consult the console-setup(5) manual page.
|
||||||
|
|
||||||
|
ACTIVE_CONSOLES="/dev/tty[1-6]"
|
||||||
|
|
||||||
|
CHARMAP="UTF-8"
|
||||||
|
|
||||||
|
# For best results with the Adafruit 2.8 LCD and Pi-hole's chronometer
|
||||||
|
CODESET="guess"
|
||||||
|
FONTFACE="Terminus"
|
||||||
|
FONTSIZE="10x20"
|
||||||
|
|
||||||
|
VIDEOMODE=
|
||||||
|
|
||||||
|
# The following is an example how to use a braille font
|
||||||
|
# FONT='lat9w-08.psf.gz brl-8x8.psf'
|
||||||
648
advanced/dnsmasq.conf.original
Normal file
648
advanced/dnsmasq.conf.original
Normal file
@@ -0,0 +1,648 @@
|
|||||||
|
# Configuration file for dnsmasq.
|
||||||
|
#
|
||||||
|
# Format is one option per line, legal options are the same
|
||||||
|
# as the long options legal on the command line. See
|
||||||
|
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
|
||||||
|
|
||||||
|
# Listen on this specific port instead of the standard DNS port
|
||||||
|
# (53). Setting this to zero completely disables DNS function,
|
||||||
|
# leaving only DHCP and/or TFTP.
|
||||||
|
#port=5353
|
||||||
|
|
||||||
|
# The following two options make you a better netizen, since they
|
||||||
|
# tell dnsmasq to filter out queries which the public DNS cannot
|
||||||
|
# answer, and which load the servers (especially the root servers)
|
||||||
|
# unnecessarily. If you have a dial-on-demand link they also stop
|
||||||
|
# these requests from bringing up the link unnecessarily.
|
||||||
|
|
||||||
|
# Never forward plain names (without a dot or domain part)
|
||||||
|
#domain-needed
|
||||||
|
# Never forward addresses in the non-routed address spaces.
|
||||||
|
#bogus-priv
|
||||||
|
|
||||||
|
# Uncomment these to enable DNSSEC validation and caching:
|
||||||
|
# (Requires dnsmasq to be built with DNSSEC option.)
|
||||||
|
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
|
||||||
|
#dnssec
|
||||||
|
|
||||||
|
# Replies which are not DNSSEC signed may be legitimate, because the domain
|
||||||
|
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
|
||||||
|
# check that an unsigned reply is OK, by finding a secure proof that a DS
|
||||||
|
# record somewhere between the root and the domain does not exist.
|
||||||
|
# The cost of setting this is that even queries in unsigned domains will need
|
||||||
|
# one or more extra DNS queries to verify.
|
||||||
|
#dnssec-check-unsigned
|
||||||
|
|
||||||
|
# Uncomment this to filter useless windows-originated DNS requests
|
||||||
|
# which can trigger dial-on-demand links needlessly.
|
||||||
|
# Note that (amongst other things) this blocks all SRV requests,
|
||||||
|
# so don't use it if you use eg Kerberos, SIP, XMMP or Google-talk.
|
||||||
|
# This option only affects forwarding, SRV records originating for
|
||||||
|
# dnsmasq (via srv-host= lines) are not suppressed by it.
|
||||||
|
#filterwin2k
|
||||||
|
|
||||||
|
# Change this line if you want dns to get its upstream servers from
|
||||||
|
# somewhere other that /etc/resolv.conf
|
||||||
|
#resolv-file=
|
||||||
|
|
||||||
|
# By default, dnsmasq will send queries to any of the upstream
|
||||||
|
# servers it knows about and tries to favour servers to are known
|
||||||
|
# to be up. Uncommenting this forces dnsmasq to try each query
|
||||||
|
# with each server strictly in the order they appear in
|
||||||
|
# /etc/resolv.conf
|
||||||
|
#strict-order
|
||||||
|
|
||||||
|
# If you don't want dnsmasq to read /etc/resolv.conf or any other
|
||||||
|
# file, getting its servers from this file instead (see below), then
|
||||||
|
# uncomment this.
|
||||||
|
#no-resolv
|
||||||
|
|
||||||
|
# If you don't want dnsmasq to poll /etc/resolv.conf or other resolv
|
||||||
|
# files for changes and re-read them then uncomment this.
|
||||||
|
#no-poll
|
||||||
|
|
||||||
|
# Add other name servers here, with domain specs if they are for
|
||||||
|
# non-public domains.
|
||||||
|
#server=/localnet/192.168.0.1
|
||||||
|
|
||||||
|
# Example of routing PTR queries to nameservers: this will send all
|
||||||
|
# address->name queries for 192.168.3/24 to nameserver 10.1.2.3
|
||||||
|
#server=/3.168.192.in-addr.arpa/10.1.2.3
|
||||||
|
|
||||||
|
# Add local-only domains here, queries in these domains are answered
|
||||||
|
# from /etc/hosts or DHCP only.
|
||||||
|
#local=/localnet/
|
||||||
|
|
||||||
|
# Add domains which you want to force to an IP address here.
|
||||||
|
# The example below send any host in double-click.net to a local
|
||||||
|
# web-server.
|
||||||
|
#address=/double-click.net/127.0.0.1
|
||||||
|
|
||||||
|
# --address (and --server) work with IPv6 addresses too.
|
||||||
|
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
|
||||||
|
|
||||||
|
# Add the IPs of all queries to yahoo.com, google.com, and their
|
||||||
|
# subdomains to the vpn and search ipsets:
|
||||||
|
#ipset=/yahoo.com/google.com/vpn,search
|
||||||
|
|
||||||
|
# You can control how dnsmasq talks to a server: this forces
|
||||||
|
# queries to 10.1.2.3 to be routed via eth1
|
||||||
|
# server=10.1.2.3@eth1
|
||||||
|
|
||||||
|
# and this sets the source (ie local) address used to talk to
|
||||||
|
# 10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that
|
||||||
|
# IP on the machine, obviously).
|
||||||
|
# server=10.1.2.3@192.168.1.1#55
|
||||||
|
|
||||||
|
# If you want dnsmasq to change uid and gid to something other
|
||||||
|
# than the default, edit the following lines.
|
||||||
|
#user=
|
||||||
|
#group=
|
||||||
|
|
||||||
|
# If you want dnsmasq to listen for DHCP and DNS requests only on
|
||||||
|
# specified interfaces (and the loopback) give the name of the
|
||||||
|
# interface (eg eth0) here.
|
||||||
|
# Repeat the line for more than one interface.
|
||||||
|
#interface=
|
||||||
|
# Or you can specify which interface _not_ to listen on
|
||||||
|
#except-interface=
|
||||||
|
# Or which to listen on by address (remember to include 127.0.0.1 if
|
||||||
|
# you use this.)
|
||||||
|
#listen-address=
|
||||||
|
# If you want dnsmasq to provide only DNS service on an interface,
|
||||||
|
# configure it as shown above, and then use the following line to
|
||||||
|
# disable DHCP and TFTP on it.
|
||||||
|
#no-dhcp-interface=
|
||||||
|
|
||||||
|
# On systems which support it, dnsmasq binds the wildcard address,
|
||||||
|
# even when it is listening on only some interfaces. It then discards
|
||||||
|
# requests that it shouldn't reply to. This has the advantage of
|
||||||
|
# working even when interfaces come and go and change address. If you
|
||||||
|
# want dnsmasq to really bind only the interfaces it is listening on,
|
||||||
|
# uncomment this option. About the only time you may need this is when
|
||||||
|
# running another nameserver on the same machine.
|
||||||
|
#bind-interfaces
|
||||||
|
|
||||||
|
# If you don't want dnsmasq to read /etc/hosts, uncomment the
|
||||||
|
# following line.
|
||||||
|
#no-hosts
|
||||||
|
# or if you want it to read another file, as well as /etc/hosts, use
|
||||||
|
# this.
|
||||||
|
#addn-hosts=/etc/banner_add_hosts
|
||||||
|
|
||||||
|
# Set this (and domain: see below) if you want to have a domain
|
||||||
|
# automatically added to simple names in a hosts-file.
|
||||||
|
#expand-hosts
|
||||||
|
|
||||||
|
# Set the domain for dnsmasq. this is optional, but if it is set, it
|
||||||
|
# does the following things.
|
||||||
|
# 1) Allows DHCP hosts to have fully qualified domain names, as long
|
||||||
|
# as the domain part matches this setting.
|
||||||
|
# 2) Sets the "domain" DHCP option thereby potentially setting the
|
||||||
|
# domain of all systems configured by DHCP
|
||||||
|
# 3) Provides the domain part for "expand-hosts"
|
||||||
|
#domain=thekelleys.org.uk
|
||||||
|
|
||||||
|
# Set a different domain for a particular subnet
|
||||||
|
#domain=wireless.thekelleys.org.uk,192.168.2.0/24
|
||||||
|
|
||||||
|
# Same idea, but range rather then subnet
|
||||||
|
#domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200
|
||||||
|
|
||||||
|
# Uncomment this to enable the integrated DHCP server, you need
|
||||||
|
# to supply the range of addresses available for lease and optionally
|
||||||
|
# a lease time. If you have more than one network, you will need to
|
||||||
|
# repeat this for each network on which you want to supply DHCP
|
||||||
|
# service.
|
||||||
|
#dhcp-range=192.168.0.50,192.168.0.150,12h
|
||||||
|
|
||||||
|
# This is an example of a DHCP range where the netmask is given. This
|
||||||
|
# is needed for networks we reach the dnsmasq DHCP server via a relay
|
||||||
|
# agent. If you don't know what a DHCP relay agent is, you probably
|
||||||
|
# don't need to worry about this.
|
||||||
|
#dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h
|
||||||
|
|
||||||
|
# This is an example of a DHCP range which sets a tag, so that
|
||||||
|
# some DHCP options may be set only for this network.
|
||||||
|
#dhcp-range=set:red,192.168.0.50,192.168.0.150
|
||||||
|
|
||||||
|
# Use this DHCP range only when the tag "green" is set.
|
||||||
|
#dhcp-range=tag:green,192.168.0.50,192.168.0.150,12h
|
||||||
|
|
||||||
|
# Specify a subnet which can't be used for dynamic address allocation,
|
||||||
|
# is available for hosts with matching --dhcp-host lines. Note that
|
||||||
|
# dhcp-host declarations will be ignored unless there is a dhcp-range
|
||||||
|
# of some type for the subnet in question.
|
||||||
|
# In this case the netmask is implied (it comes from the network
|
||||||
|
# configuration on the machine running dnsmasq) it is possible to give
|
||||||
|
# an explicit netmask instead.
|
||||||
|
#dhcp-range=192.168.0.0,static
|
||||||
|
|
||||||
|
# Enable DHCPv6. Note that the prefix-length does not need to be specified
|
||||||
|
# and defaults to 64 if missing/
|
||||||
|
#dhcp-range=1234::2, 1234::500, 64, 12h
|
||||||
|
|
||||||
|
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||||
|
#dhcp-range=1234::, ra-only
|
||||||
|
|
||||||
|
# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and
|
||||||
|
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
|
||||||
|
# hosts. Use the DHCPv4 lease to derive the name, network segment and
|
||||||
|
# MAC address and assume that the host will also have an
|
||||||
|
# IPv6 address calculated using the SLAAC alogrithm.
|
||||||
|
#dhcp-range=1234::, ra-names
|
||||||
|
|
||||||
|
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||||
|
# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.)
|
||||||
|
#dhcp-range=1234::, ra-only, 48h
|
||||||
|
|
||||||
|
# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA
|
||||||
|
# so that clients can use SLAAC addresses as well as DHCP ones.
|
||||||
|
#dhcp-range=1234::2, 1234::500, slaac
|
||||||
|
|
||||||
|
# Do Router Advertisements and stateless DHCP for this subnet. Clients will
|
||||||
|
# not get addresses from DHCP, but they will get other configuration information.
|
||||||
|
# They will use SLAAC for addresses.
|
||||||
|
#dhcp-range=1234::, ra-stateless
|
||||||
|
|
||||||
|
# Do stateless DHCP, SLAAC, and generate DNS names for SLAAC addresses
|
||||||
|
# from DHCPv4 leases.
|
||||||
|
#dhcp-range=1234::, ra-stateless, ra-names
|
||||||
|
|
||||||
|
# Do router advertisements for all subnets where we're doing DHCPv6
|
||||||
|
# Unless overriden by ra-stateless, ra-names, et al, the router
|
||||||
|
# advertisements will have the M and O bits set, so that the clients
|
||||||
|
# get addresses and configuration from DHCPv6, and the A bit reset, so the
|
||||||
|
# clients don't use SLAAC addresses.
|
||||||
|
#enable-ra
|
||||||
|
|
||||||
|
# Supply parameters for specified hosts using DHCP. There are lots
|
||||||
|
# of valid alternatives, so we will give examples of each. Note that
|
||||||
|
# IP addresses DO NOT have to be in the range given above, they just
|
||||||
|
# need to be on the same network. The order of the parameters in these
|
||||||
|
# do not matter, it's permissible to give name, address and MAC in any
|
||||||
|
# order.
|
||||||
|
|
||||||
|
# Always allocate the host with Ethernet address 11:22:33:44:55:66
|
||||||
|
# The IP address 192.168.0.60
|
||||||
|
#dhcp-host=11:22:33:44:55:66,192.168.0.60
|
||||||
|
|
||||||
|
# Always set the name of the host with hardware address
|
||||||
|
# 11:22:33:44:55:66 to be "fred"
|
||||||
|
#dhcp-host=11:22:33:44:55:66,fred
|
||||||
|
|
||||||
|
# Always give the host with Ethernet address 11:22:33:44:55:66
|
||||||
|
# the name fred and IP address 192.168.0.60 and lease time 45 minutes
|
||||||
|
#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m
|
||||||
|
|
||||||
|
# Give a host with Ethernet address 11:22:33:44:55:66 or
|
||||||
|
# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume
|
||||||
|
# that these two Ethernet interfaces will never be in use at the same
|
||||||
|
# time, and give the IP address to the second, even if it is already
|
||||||
|
# in use by the first. Useful for laptops with wired and wireless
|
||||||
|
# addresses.
|
||||||
|
#dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.60
|
||||||
|
|
||||||
|
# Give the machine which says its name is "bert" IP address
|
||||||
|
# 192.168.0.70 and an infinite lease
|
||||||
|
#dhcp-host=bert,192.168.0.70,infinite
|
||||||
|
|
||||||
|
# Always give the host with client identifier 01:02:02:04
|
||||||
|
# the IP address 192.168.0.60
|
||||||
|
#dhcp-host=id:01:02:02:04,192.168.0.60
|
||||||
|
|
||||||
|
# Always give the host with client identifier "marjorie"
|
||||||
|
# the IP address 192.168.0.60
|
||||||
|
#dhcp-host=id:marjorie,192.168.0.60
|
||||||
|
|
||||||
|
# Enable the address given for "judge" in /etc/hosts
|
||||||
|
# to be given to a machine presenting the name "judge" when
|
||||||
|
# it asks for a DHCP lease.
|
||||||
|
#dhcp-host=judge
|
||||||
|
|
||||||
|
# Never offer DHCP service to a machine whose Ethernet
|
||||||
|
# address is 11:22:33:44:55:66
|
||||||
|
#dhcp-host=11:22:33:44:55:66,ignore
|
||||||
|
|
||||||
|
# Ignore any client-id presented by the machine with Ethernet
|
||||||
|
# address 11:22:33:44:55:66. This is useful to prevent a machine
|
||||||
|
# being treated differently when running under different OS's or
|
||||||
|
# between PXE boot and OS boot.
|
||||||
|
#dhcp-host=11:22:33:44:55:66,id:*
|
||||||
|
|
||||||
|
# Send extra options which are tagged as "red" to
|
||||||
|
# the machine with Ethernet address 11:22:33:44:55:66
|
||||||
|
#dhcp-host=11:22:33:44:55:66,set:red
|
||||||
|
|
||||||
|
# Send extra options which are tagged as "red" to
|
||||||
|
# any machine with Ethernet address starting 11:22:33:
|
||||||
|
#dhcp-host=11:22:33:*:*:*,set:red
|
||||||
|
|
||||||
|
# Give a fixed IPv6 address and name to client with
|
||||||
|
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
|
||||||
|
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
|
||||||
|
# Note also the they [] around the IPv6 address are obilgatory.
|
||||||
|
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||||
|
|
||||||
|
# Ignore any clients which are not specified in dhcp-host lines
|
||||||
|
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
|
||||||
|
# This relies on the special "known" tag which is set when
|
||||||
|
# a host is matched.
|
||||||
|
#dhcp-ignore=tag:!known
|
||||||
|
|
||||||
|
# Send extra options which are tagged as "red" to any machine whose
|
||||||
|
# DHCP vendorclass string includes the substring "Linux"
|
||||||
|
#dhcp-vendorclass=set:red,Linux
|
||||||
|
|
||||||
|
# Send extra options which are tagged as "red" to any machine one
|
||||||
|
# of whose DHCP userclass strings includes the substring "accounts"
|
||||||
|
#dhcp-userclass=set:red,accounts
|
||||||
|
|
||||||
|
# Send extra options which are tagged as "red" to any machine whose
|
||||||
|
# MAC address matches the pattern.
|
||||||
|
#dhcp-mac=set:red,00:60:8C:*:*:*
|
||||||
|
|
||||||
|
# If this line is uncommented, dnsmasq will read /etc/ethers and act
|
||||||
|
# on the ethernet-address/IP pairs found there just as if they had
|
||||||
|
# been given as --dhcp-host options. Useful if you keep
|
||||||
|
# MAC-address/host mappings there for other purposes.
|
||||||
|
#read-ethers
|
||||||
|
|
||||||
|
# Send options to hosts which ask for a DHCP lease.
|
||||||
|
# See RFC 2132 for details of available options.
|
||||||
|
# Common options can be given to dnsmasq by name:
|
||||||
|
# run "dnsmasq --help dhcp" to get a list.
|
||||||
|
# Note that all the common settings, such as netmask and
|
||||||
|
# broadcast address, DNS server and default route, are given
|
||||||
|
# sane defaults by dnsmasq. You very likely will not need
|
||||||
|
# any dhcp-options. If you use Windows clients and Samba, there
|
||||||
|
# are some options which are recommended, they are detailed at the
|
||||||
|
# end of this section.
|
||||||
|
|
||||||
|
# Override the default route supplied by dnsmasq, which assumes the
|
||||||
|
# router is the same machine as the one running dnsmasq.
|
||||||
|
#dhcp-option=3,1.2.3.4
|
||||||
|
|
||||||
|
# Do the same thing, but using the option name
|
||||||
|
#dhcp-option=option:router,1.2.3.4
|
||||||
|
|
||||||
|
# Override the default route supplied by dnsmasq and send no default
|
||||||
|
# route at all. Note that this only works for the options sent by
|
||||||
|
# default (1, 3, 6, 12, 28) the same line will send a zero-length option
|
||||||
|
# for all other option numbers.
|
||||||
|
#dhcp-option=3
|
||||||
|
|
||||||
|
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
|
||||||
|
#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5
|
||||||
|
|
||||||
|
# Send DHCPv6 option. Note [] around IPv6 addresses.
|
||||||
|
#dhcp-option=option6:dns-server,[1234::77],[1234::88]
|
||||||
|
|
||||||
|
# Send DHCPv6 option for namservers as the machine running
|
||||||
|
# dnsmasq and another.
|
||||||
|
#dhcp-option=option6:dns-server,[::],[1234::88]
|
||||||
|
|
||||||
|
# Ask client to poll for option changes every six hours. (RFC4242)
|
||||||
|
#dhcp-option=option6:information-refresh-time,6h
|
||||||
|
|
||||||
|
# Set the NTP time server address to be the same machine as
|
||||||
|
# is running dnsmasq
|
||||||
|
#dhcp-option=42,0.0.0.0
|
||||||
|
|
||||||
|
# Set the NIS domain name to "welly"
|
||||||
|
#dhcp-option=40,welly
|
||||||
|
|
||||||
|
# Set the default time-to-live to 50
|
||||||
|
#dhcp-option=23,50
|
||||||
|
|
||||||
|
# Set the "all subnets are local" flag
|
||||||
|
#dhcp-option=27,1
|
||||||
|
|
||||||
|
# Send the etherboot magic flag and then etherboot options (a string).
|
||||||
|
#dhcp-option=128,e4:45:74:68:00:00
|
||||||
|
#dhcp-option=129,NIC=eepro100
|
||||||
|
|
||||||
|
# Specify an option which will only be sent to the "red" network
|
||||||
|
# (see dhcp-range for the declaration of the "red" network)
|
||||||
|
# Note that the tag: part must precede the option: part.
|
||||||
|
#dhcp-option = tag:red, option:ntp-server, 192.168.1.1
|
||||||
|
|
||||||
|
# The following DHCP options set up dnsmasq in the same way as is specified
|
||||||
|
# for the ISC dhcpcd in
|
||||||
|
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
|
||||||
|
# adapted for a typical dnsmasq installation where the host running
|
||||||
|
# dnsmasq is also the host running samba.
|
||||||
|
# you may want to uncomment some or all of them if you use
|
||||||
|
# Windows clients and Samba.
|
||||||
|
#dhcp-option=19,0 # option ip-forwarding off
|
||||||
|
#dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s)
|
||||||
|
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
|
||||||
|
#dhcp-option=46,8 # netbios node type
|
||||||
|
|
||||||
|
# Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave.
|
||||||
|
#dhcp-option=252,"\n"
|
||||||
|
|
||||||
|
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
|
||||||
|
# probably doesn't support this......
|
||||||
|
#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com
|
||||||
|
|
||||||
|
# Send RFC-3442 classless static routes (note the netmask encoding)
|
||||||
|
#dhcp-option=121,192.168.1.0/24,1.2.3.4,10.0.0.0/8,5.6.7.8
|
||||||
|
|
||||||
|
# Send vendor-class specific options encapsulated in DHCP option 43.
|
||||||
|
# The meaning of the options is defined by the vendor-class so
|
||||||
|
# options are sent only when the client supplied vendor class
|
||||||
|
# matches the class given here. (A substring match is OK, so "MSFT"
|
||||||
|
# matches "MSFT" and "MSFT 5.0"). This example sets the
|
||||||
|
# mtftp address to 0.0.0.0 for PXEClients.
|
||||||
|
#dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||||
|
|
||||||
|
# Send microsoft-specific option to tell windows to release the DHCP lease
|
||||||
|
# when it shuts down. Note the "i" flag, to tell dnsmasq to send the
|
||||||
|
# value as a four-byte integer - that's what microsoft wants. See
|
||||||
|
# http://technet2.microsoft.com/WindowsServer/en/library/a70f1bb7-d2d4-49f0-96d6-4b7414ecfaae1033.mspx?mfr=true
|
||||||
|
#dhcp-option=vendor:MSFT,2,1i
|
||||||
|
|
||||||
|
# Send the Encapsulated-vendor-class ID needed by some configurations of
|
||||||
|
# Etherboot to allow is to recognise the DHCP server.
|
||||||
|
#dhcp-option=vendor:Etherboot,60,"Etherboot"
|
||||||
|
|
||||||
|
# Send options to PXELinux. Note that we need to send the options even
|
||||||
|
# though they don't appear in the parameter request list, so we need
|
||||||
|
# to use dhcp-option-force here.
|
||||||
|
# See http://syslinux.zytor.com/pxe.php#special for details.
|
||||||
|
# Magic number - needed before anything else is recognised
|
||||||
|
#dhcp-option-force=208,f1:00:74:7e
|
||||||
|
# Configuration file name
|
||||||
|
#dhcp-option-force=209,configs/common
|
||||||
|
# Path prefix
|
||||||
|
#dhcp-option-force=210,/tftpboot/pxelinux/files/
|
||||||
|
# Reboot time. (Note 'i' to send 32-bit value)
|
||||||
|
#dhcp-option-force=211,30i
|
||||||
|
|
||||||
|
# Set the boot filename for netboot/PXE. You will only need
|
||||||
|
# this is you want to boot machines over the network and you will need
|
||||||
|
# a TFTP server; either dnsmasq's built in TFTP server or an
|
||||||
|
# external one. (See below for how to enable the TFTP server.)
|
||||||
|
#dhcp-boot=pxelinux.0
|
||||||
|
|
||||||
|
# The same as above, but use custom tftp-server instead machine running dnsmasq
|
||||||
|
#dhcp-boot=pxelinux,server.name,192.168.1.100
|
||||||
|
|
||||||
|
# Boot for Etherboot gPXE. The idea is to send two different
|
||||||
|
# filenames, the first loads gPXE, and the second tells gPXE what to
|
||||||
|
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
||||||
|
#dhcp-match=set:gpxe,175 # gPXE sends a 175 option.
|
||||||
|
#dhcp-boot=tag:!gpxe,undionly.kpxe
|
||||||
|
#dhcp-boot=mybootimage
|
||||||
|
|
||||||
|
# Encapsulated options for Etherboot gPXE. All the options are
|
||||||
|
# encapsulated within option 175
|
||||||
|
#dhcp-option=encap:175, 1, 5b # priority code
|
||||||
|
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
|
||||||
|
#dhcp-option=encap:175, 177, string # bus-id
|
||||||
|
#dhcp-option=encap:175, 189, 1b # BIOS drive code
|
||||||
|
#dhcp-option=encap:175, 190, user # iSCSI username
|
||||||
|
#dhcp-option=encap:175, 191, pass # iSCSI password
|
||||||
|
|
||||||
|
# Test for the architecture of a netboot client. PXE clients are
|
||||||
|
# supposed to send their architecture as option 93. (See RFC 4578)
|
||||||
|
#dhcp-match=peecees, option:client-arch, 0 #x86-32
|
||||||
|
#dhcp-match=itanics, option:client-arch, 2 #IA64
|
||||||
|
#dhcp-match=hammers, option:client-arch, 6 #x86-64
|
||||||
|
#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64
|
||||||
|
|
||||||
|
# Do real PXE, rather than just booting a single file, this is an
|
||||||
|
# alternative to dhcp-boot.
|
||||||
|
#pxe-prompt="What system shall I netboot?"
|
||||||
|
# or with timeout before first available action is taken:
|
||||||
|
#pxe-prompt="Press F8 for menu.", 60
|
||||||
|
|
||||||
|
# Available boot services. for PXE.
|
||||||
|
#pxe-service=x86PC, "Boot from local disk"
|
||||||
|
|
||||||
|
# Loads <tftp-root>/pxelinux.0 from dnsmasq TFTP server.
|
||||||
|
#pxe-service=x86PC, "Install Linux", pxelinux
|
||||||
|
|
||||||
|
# Loads <tftp-root>/pxelinux.0 from TFTP server at 1.2.3.4.
|
||||||
|
# Beware this fails on old PXE ROMS.
|
||||||
|
#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4
|
||||||
|
|
||||||
|
# Use bootserver on network, found my multicast or broadcast.
|
||||||
|
#pxe-service=x86PC, "Install windows from RIS server", 1
|
||||||
|
|
||||||
|
# Use bootserver at a known IP address.
|
||||||
|
#pxe-service=x86PC, "Install windows from RIS server", 1, 1.2.3.4
|
||||||
|
|
||||||
|
# If you have multicast-FTP available,
|
||||||
|
# information for that can be passed in a similar way using options 1
|
||||||
|
# to 5. See page 19 of
|
||||||
|
# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf
|
||||||
|
|
||||||
|
|
||||||
|
# Enable dnsmasq's built-in TFTP server
|
||||||
|
#enable-tftp
|
||||||
|
|
||||||
|
# Set the root directory for files available via FTP.
|
||||||
|
#tftp-root=/var/ftpd
|
||||||
|
|
||||||
|
# Make the TFTP server more secure: with this set, only files owned by
|
||||||
|
# the user dnsmasq is running as will be send over the net.
|
||||||
|
#tftp-secure
|
||||||
|
|
||||||
|
# This option stops dnsmasq from negotiating a larger blocksize for TFTP
|
||||||
|
# transfers. It will slow things down, but may rescue some broken TFTP
|
||||||
|
# clients.
|
||||||
|
#tftp-no-blocksize
|
||||||
|
|
||||||
|
# Set the boot file name only when the "red" tag is set.
|
||||||
|
#dhcp-boot=tag:red,pxelinux.red-net
|
||||||
|
|
||||||
|
# An example of dhcp-boot with an external TFTP server: the name and IP
|
||||||
|
# address of the server are given after the filename.
|
||||||
|
# Can fail with old PXE ROMS. Overridden by --pxe-service.
|
||||||
|
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
||||||
|
|
||||||
|
# If there are multiple external tftp servers having a same name
|
||||||
|
# (using /etc/hosts) then that name can be specified as the
|
||||||
|
# tftp_servername (the third option to dhcp-boot) and in that
|
||||||
|
# case dnsmasq resolves this name and returns the resultant IP
|
||||||
|
# addresses in round robin fasion. This facility can be used to
|
||||||
|
# load balance the tftp load among a set of servers.
|
||||||
|
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name
|
||||||
|
|
||||||
|
# Set the limit on DHCP leases, the default is 150
|
||||||
|
#dhcp-lease-max=150
|
||||||
|
|
||||||
|
# The DHCP server needs somewhere on disk to keep its lease database.
|
||||||
|
# This defaults to a sane location, but if you want to change it, use
|
||||||
|
# the line below.
|
||||||
|
#dhcp-leasefile=/var/lib/misc/dnsmasq.leases
|
||||||
|
|
||||||
|
# Set the DHCP server to authoritative mode. In this mode it will barge in
|
||||||
|
# and take over the lease for any client which broadcasts on the network,
|
||||||
|
# whether it has a record of the lease or not. This avoids long timeouts
|
||||||
|
# when a machine wakes up on a new network. DO NOT enable this if there's
|
||||||
|
# the slightest chance that you might end up accidentally configuring a DHCP
|
||||||
|
# server for your campus/company accidentally. The ISC server uses
|
||||||
|
# the same option, and this URL provides more information:
|
||||||
|
# http://www.isc.org/files/auth.html
|
||||||
|
#dhcp-authoritative
|
||||||
|
|
||||||
|
# Run an executable when a DHCP lease is created or destroyed.
|
||||||
|
# The arguments sent to the script are "add" or "del",
|
||||||
|
# then the MAC address, the IP address and finally the hostname
|
||||||
|
# if there is one.
|
||||||
|
#dhcp-script=/bin/echo
|
||||||
|
|
||||||
|
# Set the cachesize here.
|
||||||
|
#cache-size=150
|
||||||
|
|
||||||
|
# If you want to disable negative caching, uncomment this.
|
||||||
|
#no-negcache
|
||||||
|
|
||||||
|
# Normally responses which come from /etc/hosts and the DHCP lease
|
||||||
|
# file have Time-To-Live set as zero, which conventionally means
|
||||||
|
# do not cache further. If you are happy to trade lower load on the
|
||||||
|
# server for potentially stale date, you can set a time-to-live (in
|
||||||
|
# seconds) here.
|
||||||
|
#local-ttl=
|
||||||
|
|
||||||
|
# If you want dnsmasq to detect attempts by Verisign to send queries
|
||||||
|
# to unregistered .com and .net hosts to its sitefinder service and
|
||||||
|
# have dnsmasq instead return the correct NXDOMAIN response, uncomment
|
||||||
|
# this line. You can add similar lines to do the same for other
|
||||||
|
# registries which have implemented wildcard A records.
|
||||||
|
#bogus-nxdomain=64.94.110.11
|
||||||
|
|
||||||
|
# If you want to fix up DNS results from upstream servers, use the
|
||||||
|
# alias option. This only works for IPv4.
|
||||||
|
# This alias makes a result of 1.2.3.4 appear as 5.6.7.8
|
||||||
|
#alias=1.2.3.4,5.6.7.8
|
||||||
|
# and this maps 1.2.3.x to 5.6.7.x
|
||||||
|
#alias=1.2.3.0,5.6.7.0,255.255.255.0
|
||||||
|
# and this maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
|
||||||
|
#alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
|
||||||
|
|
||||||
|
# Change these lines if you want dnsmasq to serve MX records.
|
||||||
|
|
||||||
|
# Return an MX record named "maildomain.com" with target
|
||||||
|
# servermachine.com and preference 50
|
||||||
|
#mx-host=maildomain.com,servermachine.com,50
|
||||||
|
|
||||||
|
# Set the default target for MX records created using the localmx option.
|
||||||
|
#mx-target=servermachine.com
|
||||||
|
|
||||||
|
# Return an MX record pointing to the mx-target for all local
|
||||||
|
# machines.
|
||||||
|
#localmx
|
||||||
|
|
||||||
|
# Return an MX record pointing to itself for all local machines.
|
||||||
|
#selfmx
|
||||||
|
|
||||||
|
# Change the following lines if you want dnsmasq to serve SRV
|
||||||
|
# records. These are useful if you want to serve ldap requests for
|
||||||
|
# Active Directory and other windows-originated DNS requests.
|
||||||
|
# See RFC 2782.
|
||||||
|
# You may add multiple srv-host lines.
|
||||||
|
# The fields are <name>,<target>,<port>,<priority>,<weight>
|
||||||
|
# If the domain part if missing from the name (so that is just has the
|
||||||
|
# service and protocol sections) then the domain given by the domain=
|
||||||
|
# config option is used. (Note that expand-hosts does not need to be
|
||||||
|
# set for this to work.)
|
||||||
|
|
||||||
|
# A SRV record sending LDAP for the example.com domain to
|
||||||
|
# ldapserver.example.com port 389
|
||||||
|
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389
|
||||||
|
|
||||||
|
# A SRV record sending LDAP for the example.com domain to
|
||||||
|
# ldapserver.example.com port 389 (using domain=)
|
||||||
|
#domain=example.com
|
||||||
|
#srv-host=_ldap._tcp,ldapserver.example.com,389
|
||||||
|
|
||||||
|
# Two SRV records for LDAP, each with different priorities
|
||||||
|
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,1
|
||||||
|
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,2
|
||||||
|
|
||||||
|
# A SRV record indicating that there is no LDAP server for the domain
|
||||||
|
# example.com
|
||||||
|
#srv-host=_ldap._tcp.example.com
|
||||||
|
|
||||||
|
# The following line shows how to make dnsmasq serve an arbitrary PTR
|
||||||
|
# record. This is useful for DNS-SD. (Note that the
|
||||||
|
# domain-name expansion done for SRV records _does_not
|
||||||
|
# occur for PTR records.)
|
||||||
|
#ptr-record=_http._tcp.dns-sd-services,"New Employee Page._http._tcp.dns-sd-services"
|
||||||
|
|
||||||
|
# Change the following lines to enable dnsmasq to serve TXT records.
|
||||||
|
# These are used for things like SPF and zeroconf. (Note that the
|
||||||
|
# domain-name expansion done for SRV records _does_not
|
||||||
|
# occur for TXT records.)
|
||||||
|
|
||||||
|
#Example SPF.
|
||||||
|
#txt-record=example.com,"v=spf1 a -all"
|
||||||
|
|
||||||
|
#Example zeroconf
|
||||||
|
#txt-record=_http._tcp.example.com,name=value,paper=A4
|
||||||
|
|
||||||
|
# Provide an alias for a "local" DNS name. Note that this _only_ works
|
||||||
|
# for targets which are names from DHCP or /etc/hosts. Give host
|
||||||
|
# "bert" another name, bertrand
|
||||||
|
#cname=bertand,bert
|
||||||
|
|
||||||
|
# For debugging purposes, log each DNS query as it passes through
|
||||||
|
# dnsmasq.
|
||||||
|
#log-queries
|
||||||
|
|
||||||
|
# Log lots of extra information about DHCP transactions.
|
||||||
|
#log-dhcp
|
||||||
|
|
||||||
|
# Include another lot of configuration options.
|
||||||
|
#conf-file=/etc/dnsmasq.more.conf
|
||||||
|
#conf-dir=/etc/dnsmasq.d
|
||||||
|
|
||||||
|
# Include all the files in a directory except those ending in .bak
|
||||||
|
#conf-dir=/etc/dnsmasq.d,.bak
|
||||||
|
|
||||||
|
# Include all files in a directory which end in .conf
|
||||||
|
#conf-dir=/etc/dnsmasq.d/*.conf
|
||||||
362
advanced/index.php
Normal file
362
advanced/index.php
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
<?php
|
||||||
|
/* Pi-hole: A black hole for Internet advertisements
|
||||||
|
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
* Network-wide ad blocking via your own hardware.
|
||||||
|
*
|
||||||
|
* This file is copyright under the latest version of the EUPL.
|
||||||
|
* Please see LICENSE file for your rights under this license. */
|
||||||
|
|
||||||
|
// Sanitise HTTP_HOST output
|
||||||
|
$serverName = htmlspecialchars($_SERVER["HTTP_HOST"]);
|
||||||
|
// Remove external ipv6 brackets if any
|
||||||
|
$serverName = preg_replace('/^\[(.*)\]$/', '${1}', $serverName);
|
||||||
|
|
||||||
|
if (!is_file("/etc/pihole/setupVars.conf"))
|
||||||
|
die("[ERROR] File not found: <code>/etc/pihole/setupVars.conf</code>");
|
||||||
|
|
||||||
|
// Get values from setupVars.conf
|
||||||
|
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
|
||||||
|
$svPasswd = !empty($setupVars["WEBPASSWORD"]);
|
||||||
|
$svEmail = (!empty($setupVars["ADMIN_EMAIL"]) && filter_var($setupVars["ADMIN_EMAIL"], FILTER_VALIDATE_EMAIL)) ? $setupVars["ADMIN_EMAIL"] : "";
|
||||||
|
unset($setupVars);
|
||||||
|
|
||||||
|
// Set landing page location, found within /var/www/html/
|
||||||
|
$landPage = "../landing.php";
|
||||||
|
|
||||||
|
// Define array for hostnames to be accepted as self address for splash page
|
||||||
|
$authorizedHosts = [];
|
||||||
|
if (!empty($_SERVER["FQDN"])) {
|
||||||
|
// If setenv.add-environment = ("fqdn" => "true") is configured in lighttpd,
|
||||||
|
// append $serverName to $authorizedHosts
|
||||||
|
array_push($authorizedHosts, $serverName);
|
||||||
|
} else if (!empty($_SERVER["VIRTUAL_HOST"])) {
|
||||||
|
// Append virtual hostname to $authorizedHosts
|
||||||
|
array_push($authorizedHosts, $_SERVER["VIRTUAL_HOST"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set which extension types render as Block Page (Including "" for index.ext)
|
||||||
|
$validExtTypes = array("asp", "htm", "html", "php", "rss", "xml", "");
|
||||||
|
|
||||||
|
// Get extension of current URL
|
||||||
|
$currentUrlExt = pathinfo($_SERVER["REQUEST_URI"], PATHINFO_EXTENSION);
|
||||||
|
|
||||||
|
// Set mobile friendly viewport
|
||||||
|
$viewPort = '<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>';
|
||||||
|
|
||||||
|
// Set response header
|
||||||
|
function setHeader($type = "x") {
|
||||||
|
header("X-Pi-hole: A black hole for Internet advertisements.");
|
||||||
|
if (isset($type) && $type === "js") header("Content-Type: application/javascript");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine block page type
|
||||||
|
if ($serverName === "pi.hole") {
|
||||||
|
// Redirect to Web Interface
|
||||||
|
exit(header("Location: /admin"));
|
||||||
|
} elseif (filter_var($serverName, FILTER_VALIDATE_IP) || in_array($serverName, $authorizedHosts)) {
|
||||||
|
// Set Splash Page output
|
||||||
|
$splashPage = "
|
||||||
|
<html><head>
|
||||||
|
$viewPort
|
||||||
|
<link rel='stylesheet' href='/pihole/blockingpage.css' type='text/css'/>
|
||||||
|
</head><body id='splashpage'><img src='/admin/img/logo.svg'/><br/>Pi-<b>hole</b>: Your black hole for Internet advertisements<br><a href='/admin'>Did you mean to go to the admin panel?</a></body></html>
|
||||||
|
";
|
||||||
|
|
||||||
|
// 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 authorised 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."');
|
||||||
|
} elseif (strpos($_SERVER["REQUEST_URI"], "?") !== FALSE && isset($_SERVER["HTTP_REFERER"])) {
|
||||||
|
// Serve blank image upon receiving REQUEST_URI w/ query string & HTTP_REFERRER
|
||||||
|
// e.g: An iframe of a blocked domain
|
||||||
|
exit(setHeader().'<html>
|
||||||
|
<head><script>window.close();</script></head>
|
||||||
|
<body><img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="></body>
|
||||||
|
</html>');
|
||||||
|
} elseif (!in_array($currentUrlExt, $validExtTypes) || substr_count($_SERVER["REQUEST_URI"], "?")) {
|
||||||
|
// Serve SVG upon receiving non $validExtTypes URL extension or query string
|
||||||
|
// e.g: Not an iframe of a blocked domain, such as when browsing to a file/query directly
|
||||||
|
// QoL addition: Allow the SVG to be clicked on in order to quickly show the full Block Page
|
||||||
|
$blockImg = '<a href="/"><svg xmlns="http://www.w3.org/2000/svg" width="110" height="16"><defs><style>a {text-decoration: none;} circle {stroke: rgba(152,2,2,0.5); fill: none; stroke-width: 2;} rect {fill: rgba(152,2,2,0.5);} text {opacity: 0.3; font: 11px Arial;}</style></defs><circle cx="8" cy="8" r="7"/><rect x="10.3" y="-6" width="2" height="12" transform="rotate(45)"/><text x="19.3" y="12">Blocked by Pi-hole</text></svg></a>';
|
||||||
|
exit(setHeader()."<html>
|
||||||
|
<head>$viewPort</head>
|
||||||
|
<body>$blockImg</body>
|
||||||
|
</html>");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start processing Block Page from here */
|
||||||
|
|
||||||
|
// Define admin email address text based off $svEmail presence
|
||||||
|
$bpAskAdmin = !empty($svEmail) ? '<a href="mailto:'.$svEmail.'?subject=Site Blocked: '.$serverName.'"></a>' : "<span/>";
|
||||||
|
|
||||||
|
// Determine if at least one block list has been generated
|
||||||
|
$blocklistglob = glob("/etc/pihole/list.0.*.domains");
|
||||||
|
if ($blocklistglob === array()) {
|
||||||
|
die("[ERROR] There are no domain lists generated lists within <code>/etc/pihole/</code>! Please update gravity by running <code>pihole -g</code>, or repair Pi-hole using <code>pihole -r</code>.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get possible non-standard location of FTL's database
|
||||||
|
$FTLsettings = parse_ini_file("/etc/pihole/pihole-FTL.conf");
|
||||||
|
if (isset($FTLsettings["GRAVITYDB"])) {
|
||||||
|
$gravityDBFile = $FTLsettings["GRAVITYDB"];
|
||||||
|
} else {
|
||||||
|
$gravityDBFile = "/etc/pihole/gravity.db";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to gravity.db
|
||||||
|
try {
|
||||||
|
$db = new SQLite3($gravityDBFile, SQLITE3_OPEN_READONLY);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
die("[ERROR]: Failed to connect to gravity.db");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all adlist addresses
|
||||||
|
$adlistResults = $db->query("SELECT address FROM vw_adlist");
|
||||||
|
$adlistsUrls = array();
|
||||||
|
while ($row = $adlistResults->fetchArray()) {
|
||||||
|
array_push($adlistsUrls, $row[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($adlistsUrls))
|
||||||
|
die("[ERROR]: There are no adlists enabled");
|
||||||
|
|
||||||
|
// Get total number of blocklists (Including Whitelist, Blacklist & Wildcard lists)
|
||||||
|
$adlistsCount = count($adlistsUrls) + 3;
|
||||||
|
|
||||||
|
// Set query timeout
|
||||||
|
ini_set("default_socket_timeout", 3);
|
||||||
|
|
||||||
|
// Logic for querying blocklists
|
||||||
|
function queryAds($serverName) {
|
||||||
|
// Determine the time it takes while querying adlists
|
||||||
|
$preQueryTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
|
||||||
|
$queryAds = file("http://127.0.0.1/admin/scripts/pi-hole/php/queryads.php?domain=$serverName&bp", FILE_IGNORE_NEW_LINES);
|
||||||
|
$queryAds = array_values(array_filter(preg_replace("/data:\s+/", "", $queryAds)));
|
||||||
|
$queryTime = sprintf("%.0f", (microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]) - $preQueryTime);
|
||||||
|
|
||||||
|
// Exception Handling
|
||||||
|
try {
|
||||||
|
// Define Exceptions
|
||||||
|
if (strpos($queryAds[0], "No exact results") !== FALSE) {
|
||||||
|
// Return "none" into $queryAds array
|
||||||
|
return array("0" => "none");
|
||||||
|
} else if ($queryTime >= ini_get("default_socket_timeout")) {
|
||||||
|
// Connection Timeout
|
||||||
|
throw new Exception ("Connection timeout (".ini_get("default_socket_timeout")."s)");
|
||||||
|
} elseif (!strpos($queryAds[0], ".") !== false) {
|
||||||
|
// Unknown $queryAds output
|
||||||
|
throw new Exception ("Unhandled error message (<code>$queryAds[0]</code>)");
|
||||||
|
}
|
||||||
|
return $queryAds;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Return exception as array
|
||||||
|
return array("0" => "error", "1" => $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get results of queryads.php exact search
|
||||||
|
$queryAds = queryAds($serverName);
|
||||||
|
|
||||||
|
// Pass error through to Block Page
|
||||||
|
if ($queryAds[0] === "error")
|
||||||
|
die("[ERROR]: Unable to parse results from <i>queryads.php</i>: <code>".$queryAds[1]."</code>");
|
||||||
|
|
||||||
|
// Count total number of matching blocklists
|
||||||
|
$featuredTotal = count($queryAds);
|
||||||
|
|
||||||
|
// Place results into key => value array
|
||||||
|
$queryResults = null;
|
||||||
|
foreach ($queryAds as $str) {
|
||||||
|
$value = explode(" ", $str);
|
||||||
|
@$queryResults[$value[0]] .= "$value[1]";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if domain has been blacklisted, whitelisted, wildcarded or CNAME blocked
|
||||||
|
if (strpos($queryAds[0], "blacklist") !== FALSE) {
|
||||||
|
$notableFlagClass = "blacklist";
|
||||||
|
$adlistsUrls = array("π" => substr($queryAds[0], 2));
|
||||||
|
} elseif (strpos($queryAds[0], "whitelist") !== FALSE) {
|
||||||
|
$notableFlagClass = "noblock";
|
||||||
|
$adlistsUrls = array("π" => substr($queryAds[0], 2));
|
||||||
|
$wlInfo = "recentwl";
|
||||||
|
} elseif (strpos($queryAds[0], "wildcard") !== FALSE) {
|
||||||
|
$notableFlagClass = "wildcard";
|
||||||
|
$adlistsUrls = array("π" => substr($queryAds[0], 2));
|
||||||
|
} elseif ($queryAds[0] === "none") {
|
||||||
|
$featuredTotal = "0";
|
||||||
|
$notableFlagClass = "noblock";
|
||||||
|
|
||||||
|
// QoL addition: Determine appropriate info message if CNAME exists
|
||||||
|
// Suggests to the user that $serverName has a CNAME (alias) that may be blocked
|
||||||
|
$dnsRecord = dns_get_record("$serverName")[0];
|
||||||
|
if (array_key_exists("target", $dnsRecord)) {
|
||||||
|
$wlInfo = $dnsRecord['target'];
|
||||||
|
} else {
|
||||||
|
$wlInfo = "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set #bpOutput notification
|
||||||
|
$wlOutputClass = (isset($wlInfo) && $wlInfo === "recentwl") ? $wlInfo : "hidden";
|
||||||
|
$wlOutput = (isset($wlInfo) && $wlInfo !== "recentwl") ? "<a href='http://$wlInfo'>$wlInfo</a>" : "";
|
||||||
|
|
||||||
|
// Get Pi-hole Core version
|
||||||
|
$phVersion = exec("cd /etc/.pihole/ && git describe --long --tags");
|
||||||
|
|
||||||
|
// Print $execTime on development branches
|
||||||
|
// Testing for - is marginally faster than "git rev-parse --abbrev-ref HEAD"
|
||||||
|
if (explode("-", $phVersion)[1] != "0")
|
||||||
|
$execTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
|
||||||
|
|
||||||
|
// Please Note: Text is added via CSS to allow an admin to provide a localised
|
||||||
|
// language without the need to edit this file
|
||||||
|
|
||||||
|
setHeader();
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!-- Pi-hole: A black hole for Internet advertisements
|
||||||
|
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
* Network-wide ad blocking via your own hardware.
|
||||||
|
*
|
||||||
|
* This file is copyright under the latest version of the EUPL. -->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<?=$viewPort ?>
|
||||||
|
<meta name="robots" content="noindex,nofollow"/>
|
||||||
|
<meta http-equiv="x-dns-prefetch-control" content="off">
|
||||||
|
<link rel="shortcut icon" href="//pi.hole/admin/img/favicon.png" type="image/x-icon"/>
|
||||||
|
<link rel="stylesheet" href="//pi.hole/pihole/blockingpage.css" type="text/css"/>
|
||||||
|
<title>● <?=$serverName ?></title>
|
||||||
|
<script src="//pi.hole/admin/scripts/vendor/jquery.min.js"></script>
|
||||||
|
<script>
|
||||||
|
window.onload = function () {
|
||||||
|
<?php
|
||||||
|
// Remove href fallback from "Back to safety" button
|
||||||
|
if ($featuredTotal > 0) {
|
||||||
|
echo '$("#bpBack").removeAttr("href");';
|
||||||
|
|
||||||
|
// Enable whitelisting if JS is available
|
||||||
|
echo '$("#bpWhitelist").prop("disabled", false);';
|
||||||
|
|
||||||
|
// Enable password input if necessary
|
||||||
|
if (!empty($svPasswd)) {
|
||||||
|
echo '$("#bpWLPassword").attr("placeholder", "Password");';
|
||||||
|
echo '$("#bpWLPassword").prop("disabled", false);';
|
||||||
|
}
|
||||||
|
// Otherwise hide the input
|
||||||
|
else {
|
||||||
|
echo '$("#bpWLPassword").hide();';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body id="blockpage"><div id="bpWrapper">
|
||||||
|
<header>
|
||||||
|
<h1 id="bpTitle">
|
||||||
|
<a class="title" href="/"><?php //Website Blocked ?></a>
|
||||||
|
</h1>
|
||||||
|
<div class="spc"></div>
|
||||||
|
|
||||||
|
<input id="bpAboutToggle" type="checkbox"/>
|
||||||
|
<div id="bpAbout">
|
||||||
|
<div class="aboutPH">
|
||||||
|
<div class="aboutImg"/></div>
|
||||||
|
<p>Open Source Ad Blocker
|
||||||
|
<small>Designed for Raspberry Pi</small>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="aboutLink">
|
||||||
|
<a class="linkPH" href="https://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>
|
||||||
|
|
||||||
|
<div id="bpAlt">
|
||||||
|
<label class="altBtn" for="bpAboutToggle"><?php //Why am I here? ?></label>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div id="bpOutput" class="<?=$wlOutputClass ?>"><?=$wlOutput ?></div>
|
||||||
|
<div id="bpBlock">
|
||||||
|
<p class="blockMsg"><?=$serverName ?></p>
|
||||||
|
</div>
|
||||||
|
<?php if(isset($notableFlagClass)) { ?>
|
||||||
|
<div id="bpFlag">
|
||||||
|
<p class="flagMsg <?=$notableFlagClass ?>"></p>
|
||||||
|
</div>
|
||||||
|
<?php } ?>
|
||||||
|
<div id="bpHelpTxt"><?=$bpAskAdmin ?></div>
|
||||||
|
<div id="bpButtons" class="buttons">
|
||||||
|
<a id="bpBack" onclick="javascript:history.back()" href="about:home"></a>
|
||||||
|
<?php if ($featuredTotal > 0) echo '<label id="bpInfo" for="bpMoreToggle"></label>'; ?>
|
||||||
|
</div>
|
||||||
|
<input id="bpMoreToggle" type="checkbox">
|
||||||
|
<div id="bpMoreInfo">
|
||||||
|
<span id="bpFoundIn"><span><?=$featuredTotal ?></span><?=$adlistsCount ?></span>
|
||||||
|
<pre id='bpQueryOutput'><?php if ($featuredTotal > 0) foreach ($queryResults as $num => $value) { echo "<span>[$num]:</span>$adlistsUrls[$num]\n"; } ?></pre>
|
||||||
|
|
||||||
|
<form id="bpWLButtons" class="buttons">
|
||||||
|
<input id="bpWLDomain" type="text" value="<?=$serverName ?>" disabled/>
|
||||||
|
<input id="bpWLPassword" type="password" placeholder="Javascript disabled" disabled/><button id="bpWhitelist" type="button" disabled></button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer><span><?=date("l g:i A, F dS"); ?>.</span> Pi-hole <?=$phVersion ?> (<?=gethostname()."/".$_SERVER["SERVER_ADDR"]; if (isset($execTime)) printf("/%.2fs", $execTime); ?>)</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function add() {
|
||||||
|
$("#bpOutput").removeClass("hidden error exception");
|
||||||
|
$("#bpOutput").addClass("add");
|
||||||
|
var domain = "<?=$serverName ?>";
|
||||||
|
var pw = $("#bpWLPassword");
|
||||||
|
if(domain.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: "/admin/scripts/pi-hole/php/add.php",
|
||||||
|
method: "post",
|
||||||
|
data: {"domain":domain, "list":"white", "pw":pw.val()},
|
||||||
|
success: function(response) {
|
||||||
|
if(response.indexOf("Pi-hole blocking") !== -1) {
|
||||||
|
setTimeout(function(){window.location.reload(1);}, 10000);
|
||||||
|
$("#bpOutput").removeClass("add");
|
||||||
|
$("#bpOutput").addClass("success");
|
||||||
|
$("#bpOutput").html("");
|
||||||
|
} else {
|
||||||
|
$("#bpOutput").removeClass("add");
|
||||||
|
$("#bpOutput").addClass("error");
|
||||||
|
$("#bpOutput").html(""+response+"");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(jqXHR, exception) {
|
||||||
|
$("#bpOutput").removeClass("add");
|
||||||
|
$("#bpOutput").addClass("exception");
|
||||||
|
$("#bpOutput").html("");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
<?php if ($featuredTotal > 0) { ?>
|
||||||
|
$(document).keypress(function(e) {
|
||||||
|
if(e.which === 13 && $("#bpWLPassword").is(":focus")) {
|
||||||
|
add();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#bpWhitelist").on("click", function() {
|
||||||
|
add();
|
||||||
|
});
|
||||||
|
<?php } ?>
|
||||||
|
</script>
|
||||||
|
</body></html>
|
||||||
85
advanced/lighttpd.conf.debian
Normal file
85
advanced/lighttpd.conf.debian
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Lighttpd config 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 OVERWRITTEN 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: #
|
||||||
|
# /etc/lighttpd/external.conf #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
server.modules = (
|
||||||
|
"mod_access",
|
||||||
|
"mod_accesslog",
|
||||||
|
"mod_auth",
|
||||||
|
"mod_expire",
|
||||||
|
"mod_compress",
|
||||||
|
"mod_redirect",
|
||||||
|
"mod_setenv",
|
||||||
|
"mod_rewrite"
|
||||||
|
)
|
||||||
|
|
||||||
|
server.document-root = "/var/www/html"
|
||||||
|
server.error-handler-404 = "/pihole/index.php"
|
||||||
|
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
|
||||||
|
server.errorlog = "/var/log/lighttpd/error.log"
|
||||||
|
server.pid-file = "/var/run/lighttpd.pid"
|
||||||
|
server.username = "www-data"
|
||||||
|
server.groupname = "www-data"
|
||||||
|
server.port = 80
|
||||||
|
accesslog.filename = "/var/log/lighttpd/access.log"
|
||||||
|
accesslog.format = "%{%s}t|%V|%r|%s|%b"
|
||||||
|
|
||||||
|
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/javascript", "text/css", "text/html", "text/plain" )
|
||||||
|
|
||||||
|
mimetype.assign = ( ".png" => "image/png",
|
||||||
|
".jpg" => "image/jpeg",
|
||||||
|
".jpeg" => "image/jpeg",
|
||||||
|
".html" => "text/html",
|
||||||
|
".css" => "text/css; charset=utf-8",
|
||||||
|
".js" => "application/javascript",
|
||||||
|
".json" => "application/json",
|
||||||
|
".txt" => "text/plain",
|
||||||
|
".svg" => "image/svg+xml" )
|
||||||
|
|
||||||
|
# default listening port for IPv6 falls back to the IPv4 port
|
||||||
|
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
|
||||||
|
|
||||||
|
# Prevent Lighttpd from enabling Let's Encrypt SSL for every blocked domain
|
||||||
|
#include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
|
||||||
|
include_shell "find /etc/lighttpd/conf-enabled -name '*.conf' -a ! -name 'letsencrypt.conf' -printf 'include \"%p\"\n' 2>/dev/null"
|
||||||
|
|
||||||
|
# If the URL starts with /admin, it is the Web interface
|
||||||
|
$HTTP["url"] =~ "^/admin/" {
|
||||||
|
# Create a response header for debugging using curl -I
|
||||||
|
setenv.add-response-header = (
|
||||||
|
"X-Pi-hole" => "The Pi-hole Web interface is working!",
|
||||||
|
"X-Frame-Options" => "DENY"
|
||||||
|
)
|
||||||
|
|
||||||
|
$HTTP["url"] =~ ".ttf$" {
|
||||||
|
# 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
|
||||||
|
$HTTP["url"] =~ "^/admin/\.(.*)" {
|
||||||
|
url.access-deny = ("")
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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"
|
||||||
94
advanced/lighttpd.conf.fedora
Normal file
94
advanced/lighttpd.conf.fedora
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# lighttpd config 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 OVERWRITTEN 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: #
|
||||||
|
# /etc/lighttpd/external.conf #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
server.modules = (
|
||||||
|
"mod_access",
|
||||||
|
"mod_auth",
|
||||||
|
"mod_fastcgi",
|
||||||
|
"mod_accesslog",
|
||||||
|
"mod_expire",
|
||||||
|
"mod_compress",
|
||||||
|
"mod_redirect",
|
||||||
|
"mod_setenv",
|
||||||
|
"mod_rewrite"
|
||||||
|
)
|
||||||
|
|
||||||
|
server.document-root = "/var/www/html"
|
||||||
|
server.error-handler-404 = "/pihole/index.php"
|
||||||
|
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
|
||||||
|
server.errorlog = "/var/log/lighttpd/error.log"
|
||||||
|
server.pid-file = "/var/run/lighttpd.pid"
|
||||||
|
server.username = "lighttpd"
|
||||||
|
server.groupname = "lighttpd"
|
||||||
|
server.port = 80
|
||||||
|
accesslog.filename = "/var/log/lighttpd/access.log"
|
||||||
|
accesslog.format = "%{%s}t|%V|%r|%s|%b"
|
||||||
|
|
||||||
|
|
||||||
|
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/javascript", "text/css", "text/html", "text/plain" )
|
||||||
|
|
||||||
|
mimetype.assign = ( ".png" => "image/png",
|
||||||
|
".jpg" => "image/jpeg",
|
||||||
|
".jpeg" => "image/jpeg",
|
||||||
|
".html" => "text/html",
|
||||||
|
".css" => "text/css; charset=utf-8",
|
||||||
|
".js" => "application/javascript",
|
||||||
|
".json" => "application/json",
|
||||||
|
".txt" => "text/plain",
|
||||||
|
".svg" => "image/svg+xml" )
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
#include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
|
||||||
|
|
||||||
|
fastcgi.server = ( ".php" =>
|
||||||
|
( "localhost" =>
|
||||||
|
(
|
||||||
|
"socket" => "/tmp/php-fastcgi.socket",
|
||||||
|
"bin-path" => "/usr/bin/php-cgi"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# If the URL starts with /admin, it is the Web interface
|
||||||
|
$HTTP["url"] =~ "^/admin/" {
|
||||||
|
# Create a response header for debugging using curl -I
|
||||||
|
setenv.add-response-header = (
|
||||||
|
"X-Pi-hole" => "The Pi-hole Web interface is working!",
|
||||||
|
"X-Frame-Options" => "DENY"
|
||||||
|
)
|
||||||
|
|
||||||
|
$HTTP["url"] =~ ".ttf$" {
|
||||||
|
# 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
|
||||||
|
$HTTP["url"] =~ "^/admin/\.(.*)" {
|
||||||
|
url.access-deny = ("")
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
@@ -8,17 +8,14 @@
|
|||||||
# This file is copyright under the latest version of the EUPL.
|
# This file is copyright under the latest version of the EUPL.
|
||||||
# Please see LICENSE file for your rights under this license.
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
# shellcheck source="./advanced/Scripts/COL_TABLE"
|
|
||||||
source "/opt/pihole/COL_TABLE"
|
source "/opt/pihole/COL_TABLE"
|
||||||
# shellcheck source="./advanced/Scripts/utils.sh"
|
|
||||||
source "/opt/pihole/utils.sh"
|
|
||||||
# getFTLConfigValue() from utils.sh
|
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
read -rp " ${QST} Are you sure you would like to remove ${COL_BOLD}Pi-hole${COL_NC}? [y/N] " answer
|
read -rp " ${QST} Are you sure you would like to remove ${COL_WHITE}Pi-hole${COL_NC}? [y/N] " yn
|
||||||
case ${answer} in
|
case ${yn} in
|
||||||
[Yy]* ) break;;
|
[Yy]* ) break;;
|
||||||
* ) echo -e "${OVER} ${COL_GREEN}Uninstall has been canceled${COL_NC}"; exit 0;;
|
[Nn]* ) echo -e "${OVER} ${COL_LIGHT_GREEN}Uninstall has been cancelled${COL_NC}"; exit 0;;
|
||||||
|
* ) echo -e "${OVER} ${COL_LIGHT_GREEN}Uninstall has been cancelled${COL_NC}"; exit 0;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -27,200 +24,196 @@ str="Root user check"
|
|||||||
if [[ ${EUID} -eq 0 ]]; then
|
if [[ ${EUID} -eq 0 ]]; then
|
||||||
echo -e " ${TICK} ${str}"
|
echo -e " ${TICK} ${str}"
|
||||||
else
|
else
|
||||||
echo -e " ${CROSS} ${str}
|
# Check if sudo is actually installed
|
||||||
Script called with non-root privileges
|
# If it isn't, exit because the uninstall can not complete
|
||||||
The Pi-hole requires elevated privileges to uninstall"
|
if [ -x "$(command -v sudo)" ]; then
|
||||||
|
export SUDO="sudo"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} ${str}
|
||||||
|
Script called with non-root privileges
|
||||||
|
The Pi-hole requires elevated privleges to uninstall"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||||
|
PH_TEST="true"
|
||||||
|
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||||
|
# setupVars set in basic-install.sh
|
||||||
|
source "${setupVars}"
|
||||||
|
|
||||||
|
# distro_check() sourced from basic-install.sh
|
||||||
|
distro_check
|
||||||
|
|
||||||
|
# Install packages used by the Pi-hole
|
||||||
|
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}")
|
||||||
|
if [[ "${INSTALL_WEB_SERVER}" == true ]]; then
|
||||||
|
# Install the Web dependencies
|
||||||
|
DEPS+=("${PIHOLE_WEB_DEPS[@]}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compatability
|
||||||
|
if [ -x "$(command -v apt-get)" ]; then
|
||||||
|
# Debian Family
|
||||||
|
PKG_REMOVE=("${PKG_MANAGER}" -y remove --purge)
|
||||||
|
package_check() {
|
||||||
|
dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -c "ok installed"
|
||||||
|
}
|
||||||
|
elif [ -x "$(command -v rpm)" ]; then
|
||||||
|
# Fedora Family
|
||||||
|
PKG_REMOVE=("${PKG_MANAGER}" remove -y)
|
||||||
|
package_check() {
|
||||||
|
rpm -qa | grep "^$1-" > /dev/null
|
||||||
|
}
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} OS distribution not supported"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get paths for admin interface, log files and database files,
|
removeAndPurge() {
|
||||||
# to allow deletion where user has specified a non-default location
|
# Purge dependencies
|
||||||
ADMIN_INTERFACE_DIR=$(getFTLConfigValue "webserver.paths.webroot")$(getFTLConfigValue "webserver.paths.webhome")
|
|
||||||
FTL_LOG=$(getFTLConfigValue "files.log.ftl")
|
|
||||||
DNSMASQ_LOG=$(getFTLConfigValue "files.log.dnsmasq")
|
|
||||||
WEBSERVER_LOG=$(getFTLConfigValue "files.log.webserver")
|
|
||||||
PIHOLE_DB=$(getFTLConfigValue "files.database")
|
|
||||||
GRAVITY_DB=$(getFTLConfigValue "files.gravity")
|
|
||||||
MACVENDOR_DB=$(getFTLConfigValue "files.macvendor")
|
|
||||||
|
|
||||||
PI_HOLE_LOCAL_REPO="/etc/.pihole"
|
|
||||||
# Setting SKIP_INSTALL="true" to source the installer functions without running them
|
|
||||||
SKIP_INSTALL="true"
|
|
||||||
# shellcheck source="./automated install/basic-install.sh"
|
|
||||||
source "${PI_HOLE_LOCAL_REPO}/automated install/basic-install.sh"
|
|
||||||
# Functions and Variables sources from basic-install:
|
|
||||||
# package_manager_detect(), disable_service(), stop_service(),
|
|
||||||
# restart service() and is_command()
|
|
||||||
# PI_HOLE_CONFIG_DIR PI_HOLE_INSTALL_DIR PI_HOLE_LOCAL_REPO
|
|
||||||
|
|
||||||
removeMetaPackage() {
|
|
||||||
# Purge Pi-hole meta package
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -ne " ${INFO} Removing Pi-hole meta package...";
|
for i in "${DEPS[@]}"; do
|
||||||
eval "${PKG_REMOVE}" "pihole-meta" &> /dev/null;
|
if package_check "${i}" > /dev/null; then
|
||||||
echo -e "${OVER} ${INFO} Removed Pi-hole meta package";
|
while true; do
|
||||||
}
|
read -rp " ${QST} Do you wish to remove ${COL_WHITE}${i}${COL_NC} from your system? [Y/N] " yn
|
||||||
|
case ${yn} in
|
||||||
removeWebInterface() {
|
[Yy]* )
|
||||||
# Remove the web interface of Pi-hole
|
echo -ne " ${INFO} Removing ${i}...";
|
||||||
echo -ne " ${INFO} Removing Web Interface..."
|
${SUDO} "${PKG_REMOVE[@]}" "${i}" &> /dev/null;
|
||||||
rm -rf "${ADMIN_INTERFACE_DIR:-/var/www/html/admin/}" &> /dev/null
|
echo -e "${OVER} ${INFO} Removed ${i}";
|
||||||
echo -e "${OVER} ${TICK} Removed Web Interface"
|
break;;
|
||||||
}
|
[Nn]* ) echo -e " ${INFO} Skipped ${i}"; break;;
|
||||||
|
esac
|
||||||
removeFTL() {
|
done
|
||||||
# Remove FTL and stop any running FTL service
|
else
|
||||||
if is_command "pihole-FTL"; then
|
echo -e " ${INFO} Package ${i} not installed"
|
||||||
# service stop & disable from basic_install.sh
|
|
||||||
stop_service pihole-FTL
|
|
||||||
disable_service pihole-FTL
|
|
||||||
|
|
||||||
echo -ne " ${INFO} Removing pihole-FTL..."
|
|
||||||
rm -f /etc/systemd/system/pihole-FTL.service &> /dev/null
|
|
||||||
if [[ -d '/etc/systemd/system/pihole-FTL.service.d' ]]; then
|
|
||||||
read -rp " ${QST} FTL service override directory /etc/systemd/system/pihole-FTL.service.d detected. Do you wish to remove this from your system? [y/N] " answer
|
|
||||||
case $answer in
|
|
||||||
[yY]*)
|
|
||||||
echo -ne " ${INFO} Removing /etc/systemd/system/pihole-FTL.service.d..."
|
|
||||||
rm -R /etc/systemd/system/pihole-FTL.service.d &> /dev/null
|
|
||||||
echo -e "${OVER} ${INFO} Removed /etc/systemd/system/pihole-FTL.service.d"
|
|
||||||
;;
|
|
||||||
*) echo -e " ${INFO} Leaving /etc/systemd/system/pihole-FTL.service.d in place.";;
|
|
||||||
esac
|
|
||||||
fi
|
fi
|
||||||
rm -f /etc/init.d/pihole-FTL &> /dev/null
|
done
|
||||||
rm -f /usr/bin/pihole-FTL &> /dev/null
|
|
||||||
echo -e "${OVER} ${TICK} Removed pihole-FTL"
|
|
||||||
|
|
||||||
# Force systemd reload after service files are removed
|
# Remove dnsmasq config files
|
||||||
if is_command "systemctl"; then
|
${SUDO} rm -f /etc/dnsmasq.conf /etc/dnsmasq.conf.orig /etc/dnsmasq.d/*-pihole*.conf &> /dev/null
|
||||||
echo -ne " ${INFO} Restarting systemd..."
|
echo -e " ${TICK} Removing dnsmasq config files"
|
||||||
systemctl daemon-reload
|
|
||||||
echo -e "${OVER} ${TICK} Restarted systemd..."
|
# Call removeNoPurge to remove Pi-hole specific files
|
||||||
|
removeNoPurge
|
||||||
|
}
|
||||||
|
|
||||||
|
removeNoPurge() {
|
||||||
|
# Only web directories/files that are created by Pi-hole should be removed
|
||||||
|
echo -ne " ${INFO} Removing Web Interface..."
|
||||||
|
${SUDO} rm -rf /var/www/html/admin &> /dev/null
|
||||||
|
${SUDO} rm -rf /var/www/html/pihole &> /dev/null
|
||||||
|
${SUDO} rm -f /var/www/html/index.lighttpd.orig &> /dev/null
|
||||||
|
|
||||||
|
# If the web directory is empty after removing these files, then the parent html directory can be removed.
|
||||||
|
if [ -d "/var/www/html" ]; then
|
||||||
|
if [[ ! "$(ls -A /var/www/html)" ]]; then
|
||||||
|
${SUDO} rm -rf /var/www/html &> /dev/null
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
echo -e "${OVER} ${TICK} Removed Web Interface"
|
||||||
|
|
||||||
removeCronFiles() {
|
|
||||||
# Attempt to preserve backwards compatibility with older versions
|
# Attempt to preserve backwards compatibility with older versions
|
||||||
# to guarantee no additional changes were made to /etc/crontab after
|
# to guarantee no additional changes were made to /etc/crontab after
|
||||||
# the installation of pihole, /etc/crontab.pihole should be permanently
|
# the installation of pihole, /etc/crontab.pihole should be permanently
|
||||||
# preserved.
|
# preserved.
|
||||||
if [[ -f /etc/crontab.orig ]]; then
|
if [[ -f /etc/crontab.orig ]]; then
|
||||||
mv /etc/crontab /etc/crontab.pihole
|
${SUDO} mv /etc/crontab /etc/crontab.pihole
|
||||||
mv /etc/crontab.orig /etc/crontab
|
${SUDO} mv /etc/crontab.orig /etc/crontab
|
||||||
restart_service cron
|
${SUDO} service cron restart
|
||||||
echo -e " ${TICK} Restored the default system cron"
|
echo -e " ${TICK} Restored the default system cron"
|
||||||
echo -e " ${INFO} A backup of the most recent crontab is saved at /etc/crontab.pihole"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Attempt to preserve backwards compatibility with older versions
|
# Attempt to preserve backwards compatibility with older versions
|
||||||
if [[ -f /etc/cron.d/pihole ]];then
|
if [[ -f /etc/cron.d/pihole ]];then
|
||||||
rm -f /etc/cron.d/pihole &> /dev/null
|
${SUDO} rm -f /etc/cron.d/pihole &> /dev/null
|
||||||
echo -e " ${TICK} Removed /etc/cron.d/pihole"
|
echo -e " ${TICK} Removed /etc/cron.d/pihole"
|
||||||
fi
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
removePiholeFiles() {
|
if package_check lighttpd > /dev/null; then
|
||||||
# Remove databases (including user specified non-default paths)
|
if [[ -f /etc/lighttpd/lighttpd.conf.orig ]]; then
|
||||||
rm -f "${PIHOLE_DB:-/etc/pihole/pihole-FTL.db}" &> /dev/null
|
${SUDO} mv /etc/lighttpd/lighttpd.conf.orig /etc/lighttpd/lighttpd.conf
|
||||||
rm -f "${GRAVITY_DB:-/etc/pihole/gravity.db}" &> /dev/null
|
|
||||||
rm -f "${MACVENDOR_DB:-/etc/pihole/macvendor.db}" &> /dev/null
|
|
||||||
|
|
||||||
# Remove pihole config, repo and local files
|
|
||||||
rm -rf "${PI_HOLE_CONFIG_DIR:-/etc/pihole}" &> /dev/null
|
|
||||||
rm -rf "${PI_HOLE_LOCAL_REPO:-/etc/.pihole}" &> /dev/null
|
|
||||||
rm -rf "${PI_HOLE_INSTALL_DIR:-/opt/pihole}" &> /dev/null
|
|
||||||
|
|
||||||
# Remove log files (including user specified non-default paths)
|
|
||||||
# and rotated logs
|
|
||||||
# Explicitly escape spaces, in case of trailing space in path before wildcard
|
|
||||||
rm -f "$(printf '%q' "${FTL_LOG:-/var/log/pihole/FTL.log}")*" &> /dev/null
|
|
||||||
rm -f "$(printf '%q' "${DNSMASQ_LOG:-/var/log/pihole/pihole.log}")*" &> /dev/null
|
|
||||||
rm -f "$(printf '%q' "${WEBSERVER_LOG:-/var/log/pihole/webserver.log}")*" &> /dev/null
|
|
||||||
|
|
||||||
# remove any remnant log-files from old versions
|
|
||||||
rm -rf /var/log/*pihole* &> /dev/null
|
|
||||||
|
|
||||||
# remove log directory
|
|
||||||
rm -rf /var/log/pihole &> /dev/null
|
|
||||||
|
|
||||||
# remove the pihole command
|
|
||||||
rm -f /usr/local/bin/pihole &> /dev/null
|
|
||||||
|
|
||||||
# remove Pi-hole's bash completion
|
|
||||||
rm -f /etc/bash_completion.d/pihole &> /dev/null
|
|
||||||
rm -f /etc/bash_completion.d/pihole-FTL &> /dev/null
|
|
||||||
|
|
||||||
# Remove pihole from sudoers for compatibility with old versions
|
|
||||||
rm -f /etc/sudoers.d/pihole &> /dev/null
|
|
||||||
|
|
||||||
echo -e " ${TICK} Removed config files"
|
|
||||||
}
|
|
||||||
|
|
||||||
removeManPage() {
|
|
||||||
# If the pihole manpage exists, then delete
|
|
||||||
if [[ -f /usr/local/share/man/man8/pihole.8 ]]; then
|
|
||||||
rm -f /usr/local/share/man/man8/pihole.8 /usr/local/share/man/man8/pihole-FTL.8 /usr/local/share/man/man5/pihole-FTL.conf.5
|
|
||||||
# Rebuild man-db if present
|
|
||||||
if is_command "mandb"; then
|
|
||||||
mandb -q &>/dev/null
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -f /etc/lighttpd/external.conf ]]; then
|
||||||
|
${SUDO} rm /etc/lighttpd/external.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e " ${TICK} Removed lighttpd configs"
|
||||||
|
fi
|
||||||
|
|
||||||
|
${SUDO} rm -f /etc/dnsmasq.d/adList.conf &> /dev/null
|
||||||
|
${SUDO} rm -f /etc/dnsmasq.d/01-pihole.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
|
||||||
|
${SUDO} rm -rf /opt/pihole/ &> /dev/null
|
||||||
|
${SUDO} rm -f /usr/local/bin/pihole &> /dev/null
|
||||||
|
${SUDO} rm -f /etc/bash_completion.d/pihole &> /dev/null
|
||||||
|
${SUDO} rm -f /etc/sudoers.d/pihole &> /dev/null
|
||||||
|
echo -e " ${TICK} Removed config files"
|
||||||
|
|
||||||
|
# Restore Resolved
|
||||||
|
if [[ -e /etc/systemd/resolved.conf.orig ]]; then
|
||||||
|
${SUDO} cp -p /etc/systemd/resolved.conf.orig /etc/systemd/resolved.conf
|
||||||
|
systemctl reload-or-restart systemd-resolved
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove FTL
|
||||||
|
if command -v pihole-FTL &> /dev/null; then
|
||||||
|
echo -ne " ${INFO} Removing pihole-FTL..."
|
||||||
|
if [[ -x "$(command -v systemctl)" ]]; then
|
||||||
|
systemctl stop pihole-FTL
|
||||||
|
else
|
||||||
|
service pihole-FTL stop
|
||||||
|
fi
|
||||||
|
${SUDO} rm -f /etc/init.d/pihole-FTL
|
||||||
|
${SUDO} rm -f /usr/bin/pihole-FTL
|
||||||
|
echo -e "${OVER} ${TICK} Removed pihole-FTL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If the pihole manpage exists, then delete and rebuild man-db
|
||||||
|
if [[ -f /usr/local/share/man/man8/pihole.8 ]]; then
|
||||||
|
${SUDO} rm -f /usr/local/share/man/man8/pihole.8 /usr/local/share/man/man8/pihole-FTL.8 /usr/local/share/man/man5/pihole-FTL.conf.5
|
||||||
|
${SUDO} mandb -q &>/dev/null
|
||||||
echo -e " ${TICK} Removed pihole man page"
|
echo -e " ${TICK} Removed pihole man page"
|
||||||
fi
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
removeUser() {
|
|
||||||
# If the pihole user exists, then remove
|
# If the pihole user exists, then remove
|
||||||
if id "pihole" &> /dev/null; then
|
if id "pihole" &> /dev/null; then
|
||||||
if userdel -r pihole 2> /dev/null; then
|
if ${SUDO} userdel -r pihole 2> /dev/null; then
|
||||||
echo -e " ${TICK} Removed 'pihole' user"
|
echo -e " ${TICK} Removed 'pihole' user"
|
||||||
else
|
else
|
||||||
echo -e " ${CROSS} Unable to remove 'pihole' user"
|
echo -e " ${CROSS} Unable to remove 'pihole' user"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If the pihole group exists, then remove
|
|
||||||
if getent group "pihole" &> /dev/null; then
|
|
||||||
if groupdel pihole 2> /dev/null; then
|
|
||||||
echo -e " ${TICK} Removed 'pihole' group"
|
|
||||||
else
|
|
||||||
echo -e " ${CROSS} Unable to remove 'pihole' group"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
restoreResolved() {
|
|
||||||
# Restore Resolved from saved configuration, if present
|
|
||||||
if [[ -e /etc/systemd/resolved.conf.orig ]] || [[ -e /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf ]]; then
|
|
||||||
cp -p /etc/systemd/resolved.conf.orig /etc/systemd/resolved.conf &> /dev/null || true
|
|
||||||
rm -f /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf &> /dev/null
|
|
||||||
systemctl reload-or-restart systemd-resolved
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
completionMessage() {
|
|
||||||
echo -e "\\n We're sorry to see you go, but thanks for checking out Pi-hole!
|
echo -e "\\n We're sorry to see you go, but thanks for checking out Pi-hole!
|
||||||
If you need help, reach out to us on GitHub, Discourse, Reddit or Twitter
|
If you need help, reach out to us on Github, Discourse, Reddit or Twitter
|
||||||
Reinstall at any time: ${COL_BOLD}curl -sSL https://install.pi-hole.net | bash${COL_NC}
|
Reinstall at any time: ${COL_WHITE}curl -sSL https://install.pi-hole.net | bash${COL_NC}
|
||||||
|
|
||||||
${COL_RED}Please reset the DNS on your router/clients to restore internet connectivity${COL_NC}
|
${COL_LIGHT_RED}Please reset the DNS on your router/clients to restore internet connectivity
|
||||||
${INFO} Pi-hole's meta package has been removed, use the 'autoremove' function from your package manager to remove unused dependencies${COL_NC}
|
${COL_LIGHT_GREEN}Uninstallation Complete! ${COL_NC}"
|
||||||
${COL_GREEN}Uninstallation Complete! ${COL_NC}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
######### SCRIPT ###########
|
######### SCRIPT ###########
|
||||||
# The ordering here allows clean uninstallation with nothing
|
if command -v vcgencmd &> /dev/null; then
|
||||||
# removed before anything that depends upon it.
|
echo -e " ${INFO} All dependencies are safe to remove on Raspbian"
|
||||||
# eg removeFTL relies on scripts removed by removePiholeFiles
|
else
|
||||||
# removeUser relies on commands removed by removeMetaPackage
|
echo -e " ${INFO} Be sure to confirm if any dependencies should not be removed"
|
||||||
package_manager_detect
|
fi
|
||||||
removeWebInterface
|
while true; do
|
||||||
removeCronFiles
|
echo -e " ${INFO} ${COL_YELLOW}The following dependencies may have been added by the Pi-hole install:"
|
||||||
restoreResolved
|
echo -n " "
|
||||||
removeManPage
|
for i in "${DEPS[@]}"; do
|
||||||
removeFTL
|
echo -n "${i} "
|
||||||
removeUser
|
done
|
||||||
removeMetaPackage
|
echo "${COL_NC}"
|
||||||
removePiholeFiles
|
read -rp " ${QST} Do you wish to go through each dependency for removal? (Choosing No will leave all dependencies installed) [Y/n] " yn
|
||||||
completionMessage
|
case ${yn} in
|
||||||
|
[Yy]* ) removeAndPurge; break;;
|
||||||
|
[Nn]* ) removeNoPurge; break;;
|
||||||
|
* ) removeAndPurge; break;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|||||||
43
block hulu ads/lighttpd.conf
Normal file
43
block hulu ads/lighttpd.conf
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
|
# (c) 2015, 2016 by Jacob Salmela
|
||||||
|
# Network-wide ad blocking via your Raspberry Pi
|
||||||
|
# http://pi-hole.net
|
||||||
|
# Lighttpd config file for Pi-hole
|
||||||
|
#
|
||||||
|
# Pi-hole is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
server.modules = (
|
||||||
|
"mod_access",
|
||||||
|
"mod_alias",
|
||||||
|
"mod_compress",
|
||||||
|
"mod_redirect",
|
||||||
|
"mod_rewrite"
|
||||||
|
)
|
||||||
|
|
||||||
|
server.document-root = "/var/www"
|
||||||
|
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
|
||||||
|
server.errorlog = "/var/log/lighttpd/error.log"
|
||||||
|
server.pid-file = "/var/run/lighttpd.pid"
|
||||||
|
server.username = "www-data"
|
||||||
|
server.groupname = "www-data"
|
||||||
|
server.port = 80
|
||||||
|
|
||||||
|
|
||||||
|
index-file.names = ( "index.php", "index.html", "index.lighttpd.html" )
|
||||||
|
url.access-deny = ( "~", ".inc" )
|
||||||
|
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
|
||||||
|
|
||||||
|
compress.cache-dir = "/var/cache/lighttpd/compress/"
|
||||||
|
compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" )
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
|
||||||
|
|
||||||
|
$HTTP["host"] =~ "ads.hulu.com|ads-v-darwin.hulu.com|ads-e-darwin.hulu.com" {
|
||||||
|
url.redirect = ( ".*" => "http://192.168.1.101:8200/MediaItems/19.mov")
|
||||||
|
}
|
||||||
17
block hulu ads/minidlna.conf
Normal file
17
block hulu ads/minidlna.conf
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
|
# (c) 2015, 2016 by Jacob Salmela
|
||||||
|
# Network-wide ad blocking via your Raspberry Pi
|
||||||
|
# http://pi-hole.net
|
||||||
|
# MiniDLNA config file for Pi-hole
|
||||||
|
#
|
||||||
|
# Pi-hole is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
media_dir=V,/var/lib/minidlna/videos/
|
||||||
|
port=8200
|
||||||
|
friendly_name=pihole
|
||||||
|
serial=12345678
|
||||||
|
model_number=1
|
||||||
|
inotify=yes
|
||||||
1458
gravity.sh
1458
gravity.sh
File diff suppressed because it is too large
Load Diff
112
manpages/pihole-FTL.8
Normal file
112
manpages/pihole-FTL.8
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
.TH "Pihole-FTL" "8" "pihole-FTL" "Pi-hole" "June 2018"
|
||||||
|
.SH "NAME"
|
||||||
|
pihole-FTL - Pi-hole : The Faster-Than-Light (FTL) Engine
|
||||||
|
.br
|
||||||
|
.SH "SYNOPSIS"
|
||||||
|
\fBservice pihole-FTL \fR(\fBstart\fR|\fBstop\fR|\fBrestart\fR)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole-FTL debug\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL test\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -v\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -t\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -b\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -f\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -h\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL dnsmasq-test\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL --\fR (\fBoptions\fR)
|
||||||
|
.br
|
||||||
|
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
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\fR \fIquickly\fR!
|
||||||
|
.br
|
||||||
|
|
||||||
|
Usage
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBservice pihole-FTL start\fR
|
||||||
|
.br
|
||||||
|
Start the pihole-FTL daemon
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBservice pihole-FTL stop\fR
|
||||||
|
.br
|
||||||
|
Stop the pihole-FTL daemon
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBservice pihole-FTL restart\fR
|
||||||
|
.br
|
||||||
|
If the pihole-FTP daemon is running, stop and then start, otherwise start.
|
||||||
|
.br
|
||||||
|
|
||||||
|
Command line arguments
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBdebug\fR
|
||||||
|
.br
|
||||||
|
Don't go into daemon mode (stay in foreground) + more verbose logging
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBtest\fR
|
||||||
|
.br
|
||||||
|
Start FTL and process everything, but shut down immediately afterwards
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-v, version\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show only version
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-t, tag\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show only git tag
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-b, branch\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show only git branch FTL was compiled from
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-f, no-daemon\fR
|
||||||
|
.br
|
||||||
|
Don't go into background (daemon mode)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-h, help\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show help
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBdnsmasq-test\fR
|
||||||
|
.br
|
||||||
|
Test resolver config file syntax
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB--\fR (options)
|
||||||
|
.br
|
||||||
|
Pass options to internal dnsmasq resolver
|
||||||
|
.br
|
||||||
|
.SH "EXAMPLE"
|
||||||
|
Command line arguments can be arbitrarily combined, e.g:
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole-FTL debug test\fR
|
||||||
|
.br
|
||||||
|
|
||||||
|
Start ftl in foreground with more verbose logging, process everything and shutdown immediately
|
||||||
|
.br
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
\fBpihole\fR(8), \fBpihole-FTL.conf\fR(5)
|
||||||
|
.br
|
||||||
|
.SH "COLOPHON"
|
||||||
|
|
||||||
|
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
|
||||||
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
|
||||||
@@ -1,50 +1,54 @@
|
|||||||
.TH "Pi-hole" "8" "Pi-hole" "Pi-hole" "April 2020"
|
.TH "Pi-hole" "8" "Pi-hole" "Pi-hole" "May 2018"
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
|
|
||||||
Pi-hole : A black-hole for internet advertisements
|
Pi-hole : A black-hole for internet advertisements
|
||||||
.br
|
.br
|
||||||
.SH "SYNOPSIS"
|
.SH "SYNOPSIS"
|
||||||
|
|
||||||
\fBpihole\fR (\fB-allow\fR|\fB-deny\fR) [options] domain(s)
|
\fBpihole\fR (\fB-w\fR|\fB-b\fR|\fB--wild\fR|\fB--regex\fR) [options] domain(s)
|
||||||
.br
|
.br
|
||||||
\fBpihole\fR (\fB--allow-regex\fR|\fB--regex\fR) [options] domain(s)
|
\fBpihole -a\fR \fB-p\fR password
|
||||||
.br
|
.br
|
||||||
\fBpihole\fR (\fB--allow-wild\fR|\fB--wild\fR) [options] domain(s)
|
\fBpihole -a\fR (\fB-c|-f|-k\fR)
|
||||||
.br
|
.br
|
||||||
\fBpihole setpassword\fR password
|
\fBpihole -a\fR [\fB-r\fR hostrecord]
|
||||||
.br
|
.br
|
||||||
\fBpihole\fR \fB-d\fR [-a] [-c]
|
\fBpihole -a -e\fR email
|
||||||
|
.br
|
||||||
|
\fBpihole -a -i\fR interface
|
||||||
|
.br
|
||||||
|
\fBpihole -a -l\fR privacylevel
|
||||||
|
.br
|
||||||
|
\fBpihole -c\fR [-j|-r|-e]
|
||||||
|
.br
|
||||||
|
\fBpihole\fR \fB-d\fR [-a]
|
||||||
.br
|
.br
|
||||||
\fBpihole -f
|
\fBpihole -f
|
||||||
.br
|
.br
|
||||||
pihole -r
|
pihole -r
|
||||||
.br
|
.br
|
||||||
\fBpihole\fR \fB-t\fR [arg]
|
pihole -t
|
||||||
.br
|
.br
|
||||||
\fBpihole -g\fR
|
pihole -g\fR
|
||||||
.br
|
.br
|
||||||
\fBpihole\fR \fB-q\fR [options]
|
\fBpihole\fR -\fBq\fR [options]
|
||||||
.br
|
.br
|
||||||
\fBpihole\fR \fB-l\fR (\fBon|off|off noflush\fR)
|
\fBpihole\fR \fB-l\fR (\fBon|off|off noflush\fR)
|
||||||
.br
|
.br
|
||||||
\fBpihole -up \fR[--check-only]
|
\fBpihole -up \fR[--check-only]
|
||||||
.br
|
.br
|
||||||
\fBpihole -v\fR
|
\fBpihole -v\fR [-p|-a|-f] [-c|-l|-hash]
|
||||||
.br
|
.br
|
||||||
\fBpihole uninstall\fR
|
\fBpihole uninstall
|
||||||
.br
|
.br
|
||||||
\fBpihole status\fR
|
pihole status
|
||||||
.br
|
.br
|
||||||
\fBpihole reloaddns\fR
|
pihole restartdns\fR
|
||||||
.br
|
|
||||||
\fBpihole reloadlists\fR
|
|
||||||
.br
|
.br
|
||||||
\fBpihole\fR (\fBenable\fR|\fBdisable\fR [time])
|
\fBpihole\fR (\fBenable\fR|\fBdisable\fR [time])
|
||||||
.br
|
.br
|
||||||
\fBpihole\fR \fBcheckout\fR repo [branch]
|
\fBpihole\fR \fBcheckout\fR repo [branch]
|
||||||
.br
|
.br
|
||||||
\fBpihole\fR \fBapi\fR [verbose] endpoint
|
|
||||||
.br
|
|
||||||
\fBpihole\fR \fBhelp\fR
|
\fBpihole\fR \fBhelp\fR
|
||||||
.br
|
.br
|
||||||
.SH "DESCRIPTION"
|
.SH "DESCRIPTION"
|
||||||
@@ -52,43 +56,37 @@ pihole -r
|
|||||||
Available commands and options:
|
Available commands and options:
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBallow, allowlist\fR [options] [<domain1> <domain2 ...>]
|
\fB-w, whitelist\fR [options] [<domain1> <domain2 ...>]
|
||||||
.br
|
.br
|
||||||
Adds or removes specified domain or domains to the Allowlist
|
Adds or removes specified domain or domains tho the Whitelist
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBdeny, denylist\fR [options] [<domain1> <domain2 ...>]
|
\fB-b, blacklist\fR [options] [<domain1> <domain2 ...>]
|
||||||
.br
|
.br
|
||||||
Adds or removes specified domain or domains to the denylist
|
Adds or removes specified domain or domains to the blacklist
|
||||||
.br
|
|
||||||
|
|
||||||
\fB--regex, regex\fR [options] [<regex1> <regex2 ...>]
|
|
||||||
.br
|
|
||||||
Add or removes specified regex filter to the regex denylist
|
|
||||||
.br
|
|
||||||
|
|
||||||
\fB--allow-regex\fR [options] [<regex1> <regex2 ...>]
|
|
||||||
.br
|
|
||||||
Add or removes specified regex filter to the regex allowlist
|
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fB--wild, wildcard\fR [options] [<domain1> <domain2 ...>]
|
\fB--wild, wildcard\fR [options] [<domain1> <domain2 ...>]
|
||||||
.br
|
.br
|
||||||
Add or removes specified domain to the wildcard denylist
|
Add or removes specified domain to the wildcard blacklist
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fB--allow-wild\fR [options] [<domain1> <domain2 ...>]
|
\fB--regex, regex\fR [options] [<regex1> <regex2 ...>]
|
||||||
.br
|
.br
|
||||||
Add or removes specified domain to the wildcard allowlist
|
Add or removes specified regex filter to the regex blacklist
|
||||||
.br
|
.br
|
||||||
|
|
||||||
(Allow-/denylist manipulation options):
|
(Whitelist/Blacklist manipulation options):
|
||||||
.br
|
.br
|
||||||
not, -d, --delmode Remove domain(s) from the list
|
-d, --delmode Remove domain(s) from the list
|
||||||
.br
|
.br
|
||||||
-q, --quiet Make output less verbose
|
-nr, --noreload Update list without refreshing dnsmasq
|
||||||
.br
|
.br
|
||||||
-l, --list Display all your listed domains
|
-q, --quiet Make output less verbose
|
||||||
|
.br
|
||||||
|
-l, --list Display all your listed domains
|
||||||
|
.br
|
||||||
|
--nuke Removes all entries in a list
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fB-d, debug\fR [-a]
|
\fB-d, debug\fR [-a]
|
||||||
@@ -97,29 +95,60 @@ Available commands and options:
|
|||||||
.br
|
.br
|
||||||
|
|
||||||
-a Enable automated debugging
|
-a Enable automated debugging
|
||||||
-c Include a Pi-hole database integrity check
|
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fB-f, flush\fR [quite]
|
\fB-f, flush\fR
|
||||||
.br
|
.br
|
||||||
Flush the Pi-hole log and last 24h from the query database
|
Flush the Pi-hole log
|
||||||
.br
|
.br
|
||||||
|
|
||||||
quite Suppress output
|
\fB-r, reconfigure\fR
|
||||||
|
.br
|
||||||
|
Reconfigure or Repair Pi-hole subsystems
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fB-r, repair\fR
|
\fB-t, tail\fR
|
||||||
.br
|
|
||||||
Repair Pi-hole subsystems
|
|
||||||
.br
|
|
||||||
|
|
||||||
\fB-t, tail\fR [arg]
|
|
||||||
.br
|
.br
|
||||||
View the live output of the Pi-hole log
|
View the live output of the Pi-hole log
|
||||||
.br
|
.br
|
||||||
|
|
||||||
[arg] Optional argument to filter the log for
|
\fB-a, admin\fR [options]
|
||||||
(regular expressions are supported)
|
.br
|
||||||
|
|
||||||
|
(Admin options):
|
||||||
|
.br
|
||||||
|
-p, password Set Web Interface password
|
||||||
|
.br
|
||||||
|
-c, celsius Set Celsius as preferred temperature unit
|
||||||
|
.br
|
||||||
|
-f, fahrenheit Set Fahrenheit as preferred temperature unit
|
||||||
|
.br
|
||||||
|
-k, kelvin Set Kelvin as preferred temperature unit
|
||||||
|
.br
|
||||||
|
-r, hostrecord Add a name to the DNS associated to an
|
||||||
|
IPv4/IPv6 address
|
||||||
|
.br
|
||||||
|
-e, email Set an administrative contact address for the
|
||||||
|
Block Page
|
||||||
|
.br
|
||||||
|
-i, interface Specify dnsmasq's interface listening behavior
|
||||||
|
.br
|
||||||
|
-l, privacylevel <level> Set privacy level
|
||||||
|
(0 = lowest, 4 = highest)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-c, chronometer\fR [options]
|
||||||
|
.br
|
||||||
|
Calculates stats and displays to an LCD
|
||||||
|
.br
|
||||||
|
|
||||||
|
(Chronometer Options):
|
||||||
|
.br
|
||||||
|
-j, --json Output stats as JSON formatted string
|
||||||
|
.br
|
||||||
|
-r, --refresh Set update frequency (in seconds)
|
||||||
|
.br
|
||||||
|
-e, --exit Output stats and exit witout refreshing
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fB-g, updateGravity\fR
|
\fB-g, updateGravity\fR
|
||||||
@@ -134,9 +163,11 @@ Available commands and options:
|
|||||||
|
|
||||||
(Query options):
|
(Query options):
|
||||||
.br
|
.br
|
||||||
-partial Search the adlists for partially matching domains
|
-adlist Print the name of the block list URL
|
||||||
.br
|
.br
|
||||||
-all Return all query matches within a adlists
|
-exact Search the block lists for exact domain matches
|
||||||
|
.br
|
||||||
|
-all Return all query matches within a block list
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fB-h, --help, help\fR
|
\fB-h, --help, help\fR
|
||||||
@@ -149,14 +180,14 @@ Available commands and options:
|
|||||||
Specify whether the Pi-hole log should be used
|
Specify whether the Pi-hole log should be used
|
||||||
.br
|
.br
|
||||||
|
|
||||||
(Logging options):
|
(Logging options):
|
||||||
.br
|
.br
|
||||||
on Enable the Pi-hole log at /var/log/pihole/pihole.log
|
on Enable the Pi-hole log at /var/log/pihole.log
|
||||||
.br
|
.br
|
||||||
off Disable and flush the Pi-hole log at
|
off Disable and flush the Pi-hole log at
|
||||||
/var/log/pihole/pihole.log
|
/var/log/pihole.log
|
||||||
.br
|
.br
|
||||||
off noflush Disable the Pi-hole log at /var/log/pihole/pihole.log
|
off noflush Disable the Pi-hole log at /var/log/pihole.log
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fB-up, updatePihole\fR [--check-only]
|
\fB-up, updatePihole\fR [--check-only]
|
||||||
@@ -167,14 +198,29 @@ Available commands and options:
|
|||||||
--check-only Exit script before update is performed.
|
--check-only Exit script before update is performed.
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fB-v, version\fR
|
\fB-v, version\fR [repo] [options]
|
||||||
.br
|
.br
|
||||||
Show installed versions of Pi-hole, Web Interface & FTL
|
Show installed versions of Pi-hole, Web Interface & FTL
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBsetpassword\fR
|
|
||||||
.br
|
.br
|
||||||
Set Web Interface password
|
(repo options):
|
||||||
|
.br
|
||||||
|
-p, --pihole Only retrieve info regarding Pi-hole repository
|
||||||
|
.br
|
||||||
|
-a, --admin Only retrieve info regarding AdminLTE
|
||||||
|
repository
|
||||||
|
.br
|
||||||
|
-f, --ftl Only retrieve info regarding FTL repository
|
||||||
|
.br
|
||||||
|
(version options):
|
||||||
|
.br
|
||||||
|
-c, --current Return the current version
|
||||||
|
.br
|
||||||
|
-l, --latest Return the latest version
|
||||||
|
.br
|
||||||
|
--hash Return the Github hash from your local
|
||||||
|
repositories
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBuninstall\fR
|
\fBuninstall\fR
|
||||||
@@ -187,14 +233,14 @@ Available commands and options:
|
|||||||
Display the running status of Pi-hole subsystems
|
Display the running status of Pi-hole subsystems
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBenable\fR [time]
|
\fBenable\fR
|
||||||
.br
|
.br
|
||||||
Enable Pi-hole blocking, optionally for a set duration
|
Enable Pi-hole subsystems
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBdisable\fR [time]
|
\fBdisable\fR [time]
|
||||||
.br
|
.br
|
||||||
Disable Pi-hole blocking, optionally for a set duration
|
Disable Pi-hole subsystems, optionally for a set duration
|
||||||
.br
|
.br
|
||||||
|
|
||||||
(time options):
|
(time options):
|
||||||
@@ -204,19 +250,14 @@ Available commands and options:
|
|||||||
#m Disable Pi-hole functionality for # minute(s)
|
#m Disable Pi-hole functionality for # minute(s)
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBreloaddns\fR
|
\fBrestartdns\fR
|
||||||
.br
|
.br
|
||||||
Update the lists and flush the cache without restarting the DNS server
|
Restart Pi-hole subsystems
|
||||||
.br
|
|
||||||
|
|
||||||
\fBreloadlists\fR
|
|
||||||
.br
|
|
||||||
Update the lists WITHOUT flushing the cache or restarting the DNS server
|
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBcheckout\fR [repo] [branch]
|
\fBcheckout\fR [repo] [branch]
|
||||||
.br
|
.br
|
||||||
Switch Pi-hole subsystems to a different GitHub branch
|
Switch Pi-hole subsystems to a different Github branch
|
||||||
.br
|
.br
|
||||||
|
|
||||||
(repo options):
|
(repo options):
|
||||||
@@ -236,39 +277,22 @@ Available commands and options:
|
|||||||
.br
|
.br
|
||||||
branchname Update subsystems to the specified branchname
|
branchname Update subsystems to the specified branchname
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBapi\fR [verbose] endpoint
|
|
||||||
.br
|
|
||||||
Query the Pi-hole API at <endpoint>
|
|
||||||
.br
|
|
||||||
|
|
||||||
verbose Show authentication and status messages
|
|
||||||
.br
|
|
||||||
|
|
||||||
\fBlogrotate\fR [quite]
|
|
||||||
.br
|
|
||||||
Rotate Pi-hole's log files
|
|
||||||
.br
|
|
||||||
|
|
||||||
quite Suppress output
|
|
||||||
.br
|
|
||||||
|
|
||||||
.SH "EXAMPLE"
|
.SH "EXAMPLE"
|
||||||
|
|
||||||
Some usage examples
|
Some usage examples
|
||||||
.br
|
.br
|
||||||
|
|
||||||
Allow-/denylist manipulation
|
Whitelist/blacklist manipulation
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBpihole allow iloveads.example.com\fR
|
\fBpihole -w iloveads.example.com\fR
|
||||||
.br
|
.br
|
||||||
Allow "iloveads.example.com"
|
Adds "iloveads.example.com" to whitelist
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBpihole deny remove noads.example.com\fR
|
\fBpihole -b -d noads.example.com\fR
|
||||||
.br
|
.br
|
||||||
Removes "noads.example.com" from denylist
|
Removes "noads.example.com" from blacklist
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBpihole --wild example.com\fR
|
\fBpihole --wild example.com\fR
|
||||||
@@ -279,14 +303,14 @@ Allow-/denylist manipulation
|
|||||||
|
|
||||||
\fBpihole --regex "ad.*\\.example\\.com$"\fR
|
\fBpihole --regex "ad.*\\.example\\.com$"\fR
|
||||||
.br
|
.br
|
||||||
Adds "ad.*\\.example\\.com$" to the regex denylist.
|
Adds "ad.*\\.example\\.com$" to the regex blacklist.
|
||||||
Would block all subdomains of example.com which start with "ad"
|
Would block all subdomains of example.com which start with "ad"
|
||||||
.br
|
.br
|
||||||
|
|
||||||
Changing the Web Interface password
|
Changing the Web Interface password
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBpihole setpassword ExamplePassword\fR
|
\fBpihole -a -p ExamplePassword\fR
|
||||||
.br
|
.br
|
||||||
Change the password to "ExamplePassword"
|
Change the password to "ExamplePassword"
|
||||||
.br
|
.br
|
||||||
@@ -302,9 +326,9 @@ Updating lists from internet sources
|
|||||||
Displaying version information
|
Displaying version information
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBpihole -v\fR
|
\fBpihole -v -a -c\fR
|
||||||
.br
|
.br
|
||||||
Display the current version of Pi-hole
|
Display the current version of AdminLTE
|
||||||
.br
|
.br
|
||||||
|
|
||||||
Temporarily disabling Pi-hole
|
Temporarily disabling Pi-hole
|
||||||
@@ -328,22 +352,15 @@ Switching Pi-hole subsystem branches
|
|||||||
Switch to core development branch
|
Switch to core development branch
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBpihole networkflush\fR
|
\fBpihole arpflush\fR
|
||||||
.br
|
.br
|
||||||
Flush information stored in Pi-hole's network table
|
Flush information stored in Pi-hole's network tables
|
||||||
Add '--arp' to additionally flush the ARP table
|
|
||||||
.br
|
.br
|
||||||
|
|
||||||
\fBpihole api stats/summary\fR
|
.SH "SEE ALSO"
|
||||||
.br
|
|
||||||
Queries FTL for the stats/summary endpoint
|
|
||||||
.br
|
|
||||||
|
|
||||||
\fBpihole api verbose stats/summary\fR
|
\fBlighttpd\fR(8), \fBpihole-FTL\fR(8)
|
||||||
.br
|
.br
|
||||||
Same as above, but shows authentication and status messages
|
|
||||||
.br
|
|
||||||
|
|
||||||
.SH "COLOPHON"
|
.SH "COLOPHON"
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|||||||
698
pihole
698
pihole
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Pi-hole: A black hole for Internet advertisements
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
@@ -9,65 +9,22 @@
|
|||||||
# This file is copyright under the latest version of the EUPL.
|
# This file is copyright under the latest version of the EUPL.
|
||||||
# Please see LICENSE file for your rights under this license.
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
||||||
|
|
||||||
# PI_HOLE_BIN_DIR is not readonly here because in some functions (checkout),
|
# setupVars is not readonly here because in some functions (checkout),
|
||||||
# they might get set again when the installer is sourced. This causes an
|
# it might get set again when the installer is sourced. This causes an
|
||||||
# error due to modifying a readonly variable.
|
# error due to modifying a readonly variable.
|
||||||
PI_HOLE_BIN_DIR="/usr/local/bin"
|
setupVars="/etc/pihole/setupVars.conf"
|
||||||
|
|
||||||
readonly colfile="${PI_HOLE_SCRIPT_DIR}/COL_TABLE"
|
readonly colfile="${PI_HOLE_SCRIPT_DIR}/COL_TABLE"
|
||||||
# shellcheck source=./advanced/Scripts/COL_TABLE
|
|
||||||
source "${colfile}"
|
source "${colfile}"
|
||||||
|
|
||||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
resolver="pihole-FTL"
|
||||||
# shellcheck source=./advanced/Scripts/utils.sh
|
|
||||||
source "${utilsfile}"
|
|
||||||
|
|
||||||
# Source api functions
|
webpageFunc() {
|
||||||
readonly apifile="${PI_HOLE_SCRIPT_DIR}/api.sh"
|
source "${PI_HOLE_SCRIPT_DIR}/webpage.sh"
|
||||||
# shellcheck source=./advanced/Scripts/api.sh
|
main "$@"
|
||||||
source "${apifile}"
|
exit 0
|
||||||
|
|
||||||
versionsfile="/etc/pihole/versions"
|
|
||||||
if [ -f "${versionsfile}" ]; then
|
|
||||||
# Only source versionsfile if the file exits
|
|
||||||
# fixes a warning during installation where versionsfile does not exist yet
|
|
||||||
# but gravity calls `pihole -status` and thereby sourcing the file
|
|
||||||
# shellcheck source=/dev/null
|
|
||||||
source "${versionsfile}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# TODO: We can probably remove the reliance on this function too, just tell people to pihole-FTL --config webserver.api.password "password"
|
|
||||||
SetWebPassword() {
|
|
||||||
if [ -n "$2" ] ; then
|
|
||||||
readonly PASSWORD="$2"
|
|
||||||
readonly CONFIRM="${PASSWORD}"
|
|
||||||
else
|
|
||||||
# Prevents a bug if the user presses Ctrl+C and it continues to hide the text typed.
|
|
||||||
# So we reset the terminal via stty if the user does press Ctrl+C
|
|
||||||
trap '{ echo -e "\nNot changed" ; stty sane ; exit 1; }' INT
|
|
||||||
read -s -r -p "Enter New Password (Blank for no password): " PASSWORD
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if [ "${PASSWORD}" == "" ]; then
|
|
||||||
setFTLConfigValue "webserver.api.password" ""
|
|
||||||
echo -e " ${TICK} Password Removed"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
read -s -r -p "Confirm Password: " CONFIRM
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
|
|
||||||
# pihole-FTL will automatically hash the password
|
|
||||||
setFTLConfigValue "webserver.api.password" "${PASSWORD}"
|
|
||||||
echo -e " ${TICK} New password set"
|
|
||||||
else
|
|
||||||
echo -e " ${CROSS} Passwords don't match. Your password has not been changed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
listFunc() {
|
listFunc() {
|
||||||
@@ -76,87 +33,46 @@ listFunc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
debugFunc() {
|
debugFunc() {
|
||||||
local automated
|
local automated
|
||||||
local check_database_integrity
|
local web
|
||||||
# Pull off the `debug` leaving passed call augmentation flags in $1
|
|
||||||
shift
|
|
||||||
|
|
||||||
for value in "$@"; do
|
# Pull off the `debug` leaving passed call augmentation flags in $1
|
||||||
[[ "$value" == *"-a"* ]] && automated="true"
|
shift
|
||||||
[[ "$value" == *"-c"* ]] && check_database_integrity="true"
|
if [[ "$@" == *"-a"* ]]; then
|
||||||
[[ "$value" == *"--check_database"* ]] && check_database_integrity="true"
|
automated="true"
|
||||||
done
|
fi
|
||||||
|
if [[ "$@" == *"-w"* ]]; then
|
||||||
|
web="true"
|
||||||
|
fi
|
||||||
|
|
||||||
AUTOMATED=${automated:-} CHECK_DATABASE=${check_database_integrity:-} "${PI_HOLE_SCRIPT_DIR}"/piholeDebug.sh
|
AUTOMATED=${automated:-} WEBCALL=${web:-} "${PI_HOLE_SCRIPT_DIR}"/piholeDebug.sh
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
flushFunc() {
|
flushFunc() {
|
||||||
# unsupported in docker because it requires restarting FTL
|
"${PI_HOLE_SCRIPT_DIR}"/piholeLogFlush.sh "$@"
|
||||||
if [ -n "${DOCKER_VERSION}" ]; then
|
|
||||||
unsupportedFunc
|
|
||||||
else
|
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/piholeLogFlush.sh "$@"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Deprecated function, should be removed in the future
|
|
||||||
# use networkFlush instead
|
|
||||||
arpFunc() {
|
|
||||||
shift
|
|
||||||
echo -e " ${INFO} The 'arpflush' command is deprecated, use 'networkflush' instead"
|
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/piholeNetworkFlush.sh "$@"
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
logrotateFunc() {
|
arpFunc() {
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/piholeLogRotate.sh "$@"
|
"${PI_HOLE_SCRIPT_DIR}"/piholeARPTable.sh "$@"
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
networkFlush() {
|
|
||||||
shift
|
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/piholeNetworkFlush.sh "$@"
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePiholeFunc() {
|
updatePiholeFunc() {
|
||||||
if [ -n "${DOCKER_VERSION}" ]; then
|
shift
|
||||||
unsupportedFunc
|
"${PI_HOLE_SCRIPT_DIR}"/update.sh "$@"
|
||||||
else
|
exit 0
|
||||||
shift
|
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/update.sh "$@"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
repairPiholeFunc() {
|
reconfigurePiholeFunc() {
|
||||||
if [ -n "${DOCKER_VERSION}" ]; then
|
/etc/.pihole/automated\ install/basic-install.sh --reconfigure
|
||||||
unsupportedFunc
|
exit 0;
|
||||||
else
|
|
||||||
local skipFTL additionalFlag
|
|
||||||
skipFTL=false
|
|
||||||
# Check arguments
|
|
||||||
for var in "$@"; do
|
|
||||||
case "$var" in
|
|
||||||
"--skipFTL") skipFTL=true ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "${skipFTL}" == true ]; then
|
|
||||||
additionalFlag="--skipFTL"
|
|
||||||
else
|
|
||||||
additionalFlag=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
/etc/.pihole/automated\ install/basic-install.sh --repair ${additionalFlag}
|
|
||||||
exit 0;
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGravityFunc() {
|
updateGravityFunc() {
|
||||||
exec "${PI_HOLE_SCRIPT_DIR}"/gravity.sh "$@"
|
"${PI_HOLE_SCRIPT_DIR}"/gravity.sh "$@"
|
||||||
|
exit $?
|
||||||
}
|
}
|
||||||
|
|
||||||
queryFunc() {
|
queryFunc() {
|
||||||
@@ -166,75 +82,50 @@ queryFunc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
chronometerFunc() {
|
chronometerFunc() {
|
||||||
echo "Chronometer is gone, use PADD (https://github.com/pi-hole/PADD)"
|
shift
|
||||||
|
"${PI_HOLE_SCRIPT_DIR}"/chronometer.sh "$@"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uninstallFunc() {
|
uninstallFunc() {
|
||||||
if [ -n "${DOCKER_VERSION}" ]; then
|
"${PI_HOLE_SCRIPT_DIR}"/uninstall.sh
|
||||||
unsupportedFunc
|
|
||||||
else
|
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/uninstall.sh
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
versionFunc() {
|
|
||||||
exec "${PI_HOLE_SCRIPT_DIR}"/version.sh
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadDNS() {
|
versionFunc() {
|
||||||
local svcOption svc str output status pid icon FTL_PID_FILE sigrtmin
|
shift
|
||||||
svcOption="${1:-reload}"
|
"${PI_HOLE_SCRIPT_DIR}"/version.sh "$@"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
# get the current path to the pihole-FTL.pid
|
restartDNS() {
|
||||||
FTL_PID_FILE="$(getFTLConfigValue files.pid)"
|
local svcOption svc str output status
|
||||||
|
svcOption="${1:-}"
|
||||||
|
|
||||||
# Determine if we should reload or restart
|
# Determine if we should reload or restart restart
|
||||||
if [[ "${svcOption}" =~ "reload-lists" ]]; then
|
if [[ "${svcOption}" =~ "reload" ]]; then
|
||||||
# Reloading of the lists has been requested
|
# Using SIGHUP will NOT re-read any *.conf files
|
||||||
# Note 1: This will NOT re-read any *.conf files
|
svc="killall -s SIGHUP ${resolver}"
|
||||||
# Note 2: We cannot use killall here as it does
|
else
|
||||||
# not know about real-time signals
|
# Get PID of resolver to determine if it needs to start or restart
|
||||||
|
if pidof pihole-FTL &> /dev/null; then
|
||||||
pid="$(getFTLPID ${FTL_PID_FILE})"
|
svcOption="restart"
|
||||||
if [[ "$pid" -eq "-1" ]]; then
|
|
||||||
svc="true"
|
|
||||||
str="FTL is not running"
|
|
||||||
icon="${INFO}"
|
|
||||||
else
|
else
|
||||||
sigrtmin="$(pihole-FTL sigrtmin 2>/dev/null)"
|
svcOption="start"
|
||||||
# Make sure sigrtmin is a number, otherwise fallback to RTMIN
|
|
||||||
[[ "${sigrtmin}" =~ ^[0-9]+$ ]] || unset sigrtmin
|
|
||||||
svc="kill -${sigrtmin:-RTMIN} ${pid}"
|
|
||||||
str="Reloading DNS lists"
|
|
||||||
icon="${TICK}"
|
|
||||||
fi
|
|
||||||
elif [[ "${svcOption}" =~ "reload" ]]; then
|
|
||||||
# Reloading of the DNS cache has been requested
|
|
||||||
# Note: This will NOT re-read any *.conf files
|
|
||||||
pid="$(getFTLPID ${FTL_PID_FILE})"
|
|
||||||
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
|
fi
|
||||||
|
svc="service ${resolver} ${svcOption}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Print output to Terminal, but not to Web Admin
|
# Print output to Terminal, but not to Web Admin
|
||||||
|
str="${svcOption^}ing DNS service"
|
||||||
[[ -t 1 ]] && echo -ne " ${INFO} ${str}..."
|
[[ -t 1 ]] && echo -ne " ${INFO} ${str}..."
|
||||||
|
|
||||||
output=$( { ${svc}; } 2>&1 )
|
output=$( { ${svc}; } 2>&1 )
|
||||||
status="$?"
|
status="$?"
|
||||||
|
|
||||||
if [[ "${status}" -eq 0 ]]; then
|
if [[ "${status}" -eq 0 ]]; then
|
||||||
[[ -t 1 ]] && echo -e "${OVER} ${icon} ${str}"
|
[[ -t 1 ]] && echo -e "${OVER} ${TICK} ${str}"
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
[[ ! -t 1 ]] && local OVER=""
|
[[ ! -t 1 ]] && local OVER=""
|
||||||
@@ -245,65 +136,76 @@ reloadDNS() {
|
|||||||
|
|
||||||
piholeEnable() {
|
piholeEnable() {
|
||||||
if [[ "${2}" == "-h" ]] || [[ "${2}" == "--help" ]]; then
|
if [[ "${2}" == "-h" ]] || [[ "${2}" == "--help" ]]; then
|
||||||
echo "Usage: pihole enable/disable [time]
|
echo "Usage: pihole disable [time]
|
||||||
Example: 'pihole enable', or 'pihole disable 5m'
|
Example: 'pihole disable', or 'pihole disable 5m'
|
||||||
En- or disable Pi-hole subsystems
|
Disable Pi-hole subsystems
|
||||||
|
|
||||||
Time:
|
Time:
|
||||||
#s En-/disable Pi-hole functionality for # second(s)
|
#s Disable Pi-hole functionality for # second(s)
|
||||||
#m En-/disable Pi-hole functionality for # minute(s)"
|
#m Disable Pi-hole functionality for # minute(s)"
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
fi
|
elif [[ "${1}" == "0" ]]; then
|
||||||
|
# Disable Pi-hole
|
||||||
# Get timer
|
if grep -cq "BLOCKING_ENABLED=false" "${setupVars}"; then
|
||||||
local tt="null"
|
echo -e " ${INFO} Blocking already disabled, nothing to do"
|
||||||
if [[ $# -gt 1 ]]; then
|
exit 0
|
||||||
local error=false
|
fi
|
||||||
if [[ "${2}" == *"s" ]]; then
|
if [[ $# > 1 ]]; then
|
||||||
tt=${2%"s"}
|
local error=false
|
||||||
if [[ ! "${tt}" =~ ^-?[0-9]+$ ]];then
|
if [[ "${2}" == *"s" ]]; then
|
||||||
|
tt=${2%"s"}
|
||||||
|
if [[ "${tt}" =~ ^-?[0-9]+$ ]];then
|
||||||
|
local str="Disabling blocking for ${tt} seconds"
|
||||||
|
echo -e " ${INFO} ${str}..."
|
||||||
|
local str="Blocking will be re-enabled in ${tt} seconds"
|
||||||
|
nohup bash -c "sleep ${tt}; pihole enable" </dev/null &>/dev/null &
|
||||||
|
else
|
||||||
|
local error=true
|
||||||
|
fi
|
||||||
|
elif [[ "${2}" == *"m" ]]; then
|
||||||
|
tt=${2%"m"}
|
||||||
|
if [[ "${tt}" =~ ^-?[0-9]+$ ]];then
|
||||||
|
local str="Disabling blocking for ${tt} minutes"
|
||||||
|
echo -e " ${INFO} ${str}..."
|
||||||
|
local str="Blocking will be re-enabled in ${tt} minutes"
|
||||||
|
tt=$((${tt}*60))
|
||||||
|
nohup bash -c "sleep ${tt}; pihole enable" </dev/null &>/dev/null &
|
||||||
|
else
|
||||||
|
local error=true
|
||||||
|
fi
|
||||||
|
elif [[ -n "${2}" ]]; then
|
||||||
local error=true
|
local error=true
|
||||||
fi
|
|
||||||
elif [[ "${2}" == *"m" ]]; then
|
|
||||||
tt=${2%"m"}
|
|
||||||
if [[ "${tt}" =~ ^-?[0-9]+$ ]];then
|
|
||||||
tt=$((${tt}*60))
|
|
||||||
else
|
else
|
||||||
local error=true
|
echo -e " ${INFO} Disabling blocking"
|
||||||
fi
|
fi
|
||||||
elif [[ -n "${2}" ]]; then
|
|
||||||
local error=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${error} == true ]];then
|
if [[ ${error} == true ]];then
|
||||||
echo -e " ${COL_RED}Unknown format for blocking timer!${COL_NC}"
|
echo -e " ${COL_LIGHT_RED}Unknown format for delayed reactivation of the blocking!${COL_NC}"
|
||||||
echo -e " Try 'pihole disable --help' for more information."
|
echo -e " Try 'pihole disable --help' for more information."
|
||||||
exit 1
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local str="Pi-hole Disabled"
|
||||||
|
sed -i "/BLOCKING_ENABLED=/d" "${setupVars}"
|
||||||
|
echo "BLOCKING_ENABLED=false" >> "${setupVars}"
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
# Enable Pi-hole
|
||||||
|
if grep -cq "BLOCKING_ENABLED=true" "${setupVars}"; then
|
||||||
|
echo -e " ${INFO} Blocking already enabled, nothing to do"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo -e " ${INFO} Enabling blocking"
|
||||||
|
local str="Pi-hole Enabled"
|
||||||
|
|
||||||
|
sed -i "/BLOCKING_ENABLED=/d" "${setupVars}"
|
||||||
|
echo "BLOCKING_ENABLED=true" >> "${setupVars}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Authenticate with the API
|
restartDNS reload
|
||||||
LoginAPI
|
|
||||||
|
|
||||||
# Send the request
|
|
||||||
data=$(PostFTLData "dns/blocking" "{ \"blocking\": ${1}, \"timer\": ${tt} }")
|
|
||||||
|
|
||||||
# Check the response
|
|
||||||
local extra timer
|
|
||||||
extra=" forever"
|
|
||||||
timer="$(echo "${data}"| jq --raw-output '.timer' )"
|
|
||||||
if [[ "${timer}" != "null" ]]; then
|
|
||||||
extra=" for ${timer}s"
|
|
||||||
fi
|
|
||||||
local str
|
|
||||||
str="Pi-hole $(echo "${data}" | jq --raw-output '.blocking')${extra}"
|
|
||||||
|
|
||||||
# Logout from the API
|
|
||||||
LogoutAPI
|
|
||||||
|
|
||||||
echo -e "${OVER} ${TICK} ${str}"
|
echo -e "${OVER} ${TICK} ${str}"
|
||||||
exit 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
piholeLogging() {
|
piholeLogging() {
|
||||||
@@ -314,189 +216,150 @@ Example: 'pihole logging on'
|
|||||||
Specify whether the Pi-hole log should be used
|
Specify whether the Pi-hole log should be used
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
on Enable the Pi-hole log at /var/log/pihole/pihole.log
|
on Enable the Pi-hole log at /var/log/pihole.log
|
||||||
off Disable and flush the Pi-hole log at /var/log/pihole/pihole.log
|
off Disable and flush the Pi-hole log at /var/log/pihole.log
|
||||||
off noflush Disable the Pi-hole log at /var/log/pihole/pihole.log"
|
off noflush Disable the Pi-hole log at /var/log/pihole.log"
|
||||||
exit 0
|
exit 0
|
||||||
elif [[ "${1}" == "off" ]]; then
|
elif [[ "${1}" == "off" ]]; then
|
||||||
# Disable logging
|
# Disable logging
|
||||||
setFTLConfigValue dns.queryLogging 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
|
if [[ "${2}" != "noflush" ]]; then
|
||||||
# Flush logs
|
# Flush logs
|
||||||
"${PI_HOLE_BIN_DIR}"/pihole -f
|
pihole -f
|
||||||
fi
|
fi
|
||||||
echo -e " ${INFO} Disabling logging..."
|
echo -e " ${INFO} Disabling logging..."
|
||||||
local str="Logging has been disabled!"
|
local str="Logging has been disabled!"
|
||||||
elif [[ "${1}" == "on" ]]; then
|
elif [[ "${1}" == "on" ]]; then
|
||||||
# Enable logging
|
# Enable logging
|
||||||
setFTLConfigValue dns.queryLogging 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..."
|
echo -e " ${INFO} Enabling logging..."
|
||||||
local str="Logging has been enabled!"
|
local str="Logging has been enabled!"
|
||||||
else
|
else
|
||||||
echo -e " ${COL_RED}Invalid option${COL_NC}
|
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}
|
||||||
Try 'pihole logging --help' for more information."
|
Try 'pihole logging --help' for more information."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
restartDNS
|
||||||
echo -e "${OVER} ${TICK} ${str}"
|
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() {
|
statusFunc() {
|
||||||
# Determine if there is pihole-FTL service is listening
|
# Determine if service is running on port 53 (Cr: https://superuser.com/a/806331)
|
||||||
local pid port ftl_pid_file block_status
|
if (echo > /dev/tcp/127.0.0.1/53) >/dev/null 2>&1; then
|
||||||
|
if [[ "${1}" != "web" ]]; then
|
||||||
ftl_pid_file="$(getFTLConfigValue files.pid)"
|
echo -e " ${TICK} DNS service is running"
|
||||||
|
|
||||||
pid="$(getFTLPID ${ftl_pid_file})"
|
|
||||||
|
|
||||||
if [[ "$pid" -eq "-1" ]]; then
|
|
||||||
case "${1}" in
|
|
||||||
"web") echo "-1";;
|
|
||||||
*) echo -e " ${CROSS} DNS service is NOT running";;
|
|
||||||
esac
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
# get the DNS port pihole-FTL is listening on
|
|
||||||
port="$(getFTLConfigValue dns.port)"
|
|
||||||
if [[ "${port}" == "0" ]]; then
|
|
||||||
case "${1}" in
|
|
||||||
"web") echo "-1";;
|
|
||||||
*) echo -e " ${CROSS} DNS service is NOT listening";;
|
|
||||||
esac
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
if [[ "${1}" != "web" ]]; then
|
|
||||||
echo -e " ${TICK} FTL is listening on port ${port}"
|
|
||||||
analyze_ports "${port}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
case "${1}" in
|
||||||
|
"web") echo "-1";;
|
||||||
|
*) echo -e " ${CROSS} DNS service is NOT running";;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
# Determine if Pi-hole's blocking is enabled
|
# Determine if Pi-hole's blocking is enabled
|
||||||
block_status=$(getFTLConfigValue dns.blocking.active)
|
if grep -q "BLOCKING_ENABLED=false" /etc/pihole/setupVars.conf; then
|
||||||
if [ ${block_status} == "true" ]; then
|
# A config is commented out
|
||||||
case "${1}" in
|
|
||||||
"web") echo "$port";;
|
|
||||||
*) echo -e " ${TICK} Pi-hole blocking is enabled";;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
case "${1}" in
|
case "${1}" in
|
||||||
"web") echo 0;;
|
"web") echo 0;;
|
||||||
*) echo -e " ${CROSS} Pi-hole blocking is disabled";;
|
*) echo -e " ${CROSS} Pi-hole blocking is Disabled";;
|
||||||
esac
|
esac
|
||||||
|
elif grep -q "BLOCKING_ENABLED=true" /etc/pihole/setupVars.conf; then
|
||||||
|
# Configs are set
|
||||||
|
case "${1}" in
|
||||||
|
"web") echo 1;;
|
||||||
|
*) echo -e " ${TICK} Pi-hole blocking is Enabled";;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
# No configs were found
|
||||||
|
case "${1}" in
|
||||||
|
"web") echo 99;;
|
||||||
|
*) echo -e " ${INFO} Pi-hole blocking will be enabled";;
|
||||||
|
esac
|
||||||
|
# Enable blocking
|
||||||
|
pihole enable
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tailFunc() {
|
tailFunc() {
|
||||||
# Warn user if Pi-hole's logging is disabled
|
# Warn user if Pi-hole's logging is disabled
|
||||||
local logging_enabled
|
local logging_enabled=$(grep -c "^log-queries" /etc/dnsmasq.d/01-pihole.conf)
|
||||||
logging_enabled=$(getFTLConfigValue dns.queryLogging)
|
if [[ "${logging_enabled}" == "0" ]]; then
|
||||||
if [[ "${logging_enabled}" != "true" ]]; then
|
# No "log-queries" lines are found.
|
||||||
|
# Commented out lines (such as "#log-queries") are ignored
|
||||||
echo " ${CROSS} Warning: Query logging is disabled"
|
echo " ${CROSS} Warning: Query logging is disabled"
|
||||||
fi
|
fi
|
||||||
echo -e " ${INFO} Press Ctrl-C to exit"
|
echo -e " ${INFO} Press Ctrl-C to exit"
|
||||||
|
|
||||||
# Get logfile path
|
# Retrieve IPv4/6 addresses
|
||||||
LOGFILE=$(getFTLConfigValue files.log.dnsmasq)
|
source /etc/pihole/setupVars.conf
|
||||||
readonly LOGFILE
|
|
||||||
|
|
||||||
# Strip date from each line
|
# Strip date from each line
|
||||||
# Color blocklist/denylist/wildcard entries as red
|
# Colour blocklist/blacklist/wildcard entries as red
|
||||||
# Color A/AAAA/DHCP strings as white
|
# Colour A/AAAA/DHCP strings as white
|
||||||
# Color everything else as gray
|
# Colour everything else as gray
|
||||||
tail -f $LOGFILE | 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,($(date +'%b %d ')| dnsmasq[.*[0-9]]),,g" \
|
||||||
-e "s,(.*(denied |gravity blocked ).*),${COL_RED}&${COL_NC}," \
|
-e "s,(.*(gravity |black |regex | config ).* 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,.*(query\\[A|DHCP).*,${COL_NC}&${COL_NC}," \
|
||||||
-e "s,.*,${COL_GRAY}&${COL_NC},"
|
-e "s,.*,${COL_GRAY}&${COL_NC},"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
piholeCheckoutFunc() {
|
piholeCheckoutFunc() {
|
||||||
if [ -n "${DOCKER_VERSION}" ]; then
|
if [[ "$2" == "-h" ]] || [[ "$2" == "--help" ]]; then
|
||||||
echo -e "${CROSS} Function not supported in Docker images"
|
echo "Usage: pihole checkout [repo] [branch]
|
||||||
echo "Please build a custom image following the steps at"
|
Example: 'pihole checkout master' or 'pihole checkout core dev'
|
||||||
echo "https://github.com/pi-hole/docker-pi-hole?tab=readme-ov-file#building-the-image-locally"
|
Switch Pi-hole subsystems to a different Github branch
|
||||||
|
|
||||||
|
Repositories:
|
||||||
|
core [branch] Change the branch of Pi-hole's core subsystem
|
||||||
|
web [branch] Change the branch of Web Interface subsystem
|
||||||
|
ftl [branch] Change the branch of Pi-hole's FTL subsystem
|
||||||
|
|
||||||
|
Branches:
|
||||||
|
master Update subsystems to the latest stable release
|
||||||
|
dev Update subsystems to the latest development release
|
||||||
|
branchname Update subsystems to the specified branchname"
|
||||||
exit 0
|
exit 0
|
||||||
else
|
|
||||||
if [[ "$2" == "-h" ]] || [[ "$2" == "--help" ]]; then
|
|
||||||
echo "Switch Pi-hole subsystems to a different GitHub branch
|
|
||||||
Usage: ${COL_GREEN}pihole checkout${COL_NC} ${COL_YELLOW}shortcut${COL_NC}
|
|
||||||
or ${COL_GREEN}pihole checkout${COL_NC} ${COL_PURPLE}repo${COL_NC} ${COL_CYAN}branch${COL_NC}
|
|
||||||
|
|
||||||
Example: ${COL_GREEN}pihole checkout${COL_NC} ${COL_YELLOW}master${COL_NC}
|
|
||||||
or ${COL_GREEN}pihole checkout${COL_NC} ${COL_PURPLE}ftl ${COL_CYAN}development${COL_NC}
|
|
||||||
|
|
||||||
Shortcuts:
|
|
||||||
${COL_YELLOW}master${COL_NC} Update all subsystems to the latest stable release
|
|
||||||
${COL_YELLOW}dev${COL_NC} Update all subsystems to the latest development release
|
|
||||||
|
|
||||||
Individual components:
|
|
||||||
${COL_PURPLE}core${COL_NC} ${COL_CYAN}branch${COL_NC} Change the branch of Pi-hole's core subsystem
|
|
||||||
${COL_PURPLE}web${COL_NC} ${COL_CYAN}branch${COL_NC} Change the branch of the web interface subsystem
|
|
||||||
${COL_PURPLE}ftl${COL_NC} ${COL_CYAN}branch${COL_NC} Change the branch of Pi-hole's FTL subsystem"
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
#shellcheck source=./advanced/Scripts/piholeCheckout.sh
|
|
||||||
source "${PI_HOLE_SCRIPT_DIR}"/piholeCheckout.sh
|
|
||||||
shift
|
|
||||||
checkout "$@"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
source "${PI_HOLE_SCRIPT_DIR}"/piholeCheckout.sh
|
||||||
|
shift
|
||||||
|
checkout "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
tricorderFunc() {
|
tricorderFunc() {
|
||||||
local tricorder_token
|
|
||||||
if [[ ! -p "/dev/stdin" ]]; then
|
if [[ ! -p "/dev/stdin" ]]; then
|
||||||
echo -e " ${INFO} Please do not call Tricorder directly"
|
echo -e " ${INFO} Please do not call Tricorder directly"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tricorder_token=$(curl --silent --fail --show-error --upload-file "-" https://tricorder.pi-hole.net/upload < /dev/stdin 2>&1)
|
if ! (echo > /dev/tcp/tricorder.pi-hole.net/9998) >/dev/null 2>&1; then
|
||||||
if [[ "${tricorder_token}" != "https://tricorder.pi-hole.net/"* ]]; then
|
echo -e " ${CROSS} Unable to connect to Pi-hole's Tricorder server"
|
||||||
echo -e "${CROSS} uploading failed, contact Pi-hole support for assistance."
|
exit 1
|
||||||
# Log curl error (if available)
|
fi
|
||||||
if [ -n "${tricorder_token}" ]; then
|
|
||||||
echo -e "${INFO} Error message: ${COL_RED}${tricorder_token}${COL_NC}\\n"
|
if command -v openssl &> /dev/null; then
|
||||||
tricorder_token=""
|
openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin
|
||||||
fi
|
exit "$?"
|
||||||
exit 1
|
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
|
fi
|
||||||
echo "Upload successful, your token is: ${COL_GREEN}${tricorder_token}${COL_NC}"
|
|
||||||
exit 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCheckFunc() {
|
updateCheckFunc() {
|
||||||
@@ -504,43 +367,30 @@ updateCheckFunc() {
|
|||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
unsupportedFunc(){
|
|
||||||
echo "Function not supported in Docker images"
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
helpFunc() {
|
helpFunc() {
|
||||||
echo "Usage: pihole [options]
|
echo "Usage: pihole [options]
|
||||||
Example: 'pihole allow -h'
|
Example: 'pihole -w -h'
|
||||||
Add '-h' after specific commands for more information on usage
|
Add '-h' after specific commands for more information on usage
|
||||||
|
|
||||||
Domain Options:
|
Whitelist/Blacklist Options:
|
||||||
allow, allowlist Allow domain(s)
|
-w, whitelist Whitelist domain(s)
|
||||||
deny, denylist Deny domain(s)
|
-b, blacklist Blacklist domain(s)
|
||||||
--regex, regex Regex deny domains(s)
|
--wild, wildcard Wildcard blacklist domain(s)
|
||||||
--allow-regex Regex allow domains(s)
|
--regex, regex Regex blacklist domains(s)
|
||||||
--wild, wildcard Wildcard deny domain(s)
|
Add '-h' for more info on whitelist/blacklist usage
|
||||||
--allow-wild Wildcard allow domain(s)
|
|
||||||
Add '-h' for more info on allow/deny usage
|
|
||||||
|
|
||||||
Debugging Options:
|
Debugging Options:
|
||||||
-d, debug Start a debugging session
|
-d, debug Start a debugging session
|
||||||
Add '-c' or '--check-database' to include a Pi-hole database integrity check
|
Add '-a' to enable automated debugging
|
||||||
Add '-a' to automatically upload the log to tricorder.pi-hole.net
|
-f, flush Flush the Pi-hole log
|
||||||
-f, flush Flush the Pi-hole logs and last 24h from the query database
|
-r, reconfigure Reconfigure or Repair Pi-hole subsystems
|
||||||
Add 'quiet' to suppress output messages
|
-t, tail View the live output of the Pi-hole log
|
||||||
-r, repair 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)
|
|
||||||
api <endpoint> Query the Pi-hole API at <endpoint>
|
|
||||||
Precede <endpoint> with 'verbose' option to show authentication and status messages
|
|
||||||
|
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
setpassword [pwd] Set the password for the web interface
|
-a, admin Web interface options
|
||||||
Without optional argument, password is read interactively.
|
Add '-h' for more info on Web Interface usage
|
||||||
When specifying a password directly, enclose it in single quotes.
|
-c, chronometer Calculates stats and displays to an LCD
|
||||||
|
Add '-h' for more info on chronometer usage
|
||||||
-g, updateGravity Update the list of ad-serving domains
|
-g, updateGravity Update the list of ad-serving domains
|
||||||
-h, --help, help Show this help dialog
|
-h, --help, help Show this help dialog
|
||||||
-l, logging Specify whether the Pi-hole log should be used
|
-l, logging Specify whether the Pi-hole log should be used
|
||||||
@@ -550,20 +400,16 @@ Options:
|
|||||||
-up, updatePihole Update Pi-hole subsystems
|
-up, updatePihole Update Pi-hole subsystems
|
||||||
Add '--check-only' to exit script before update is performed.
|
Add '--check-only' to exit script before update is performed.
|
||||||
-v, version Show installed versions of Pi-hole, Web Interface & FTL
|
-v, version Show installed versions of Pi-hole, Web Interface & FTL
|
||||||
|
Add '-h' for more info on version usage
|
||||||
uninstall Uninstall Pi-hole from your system
|
uninstall Uninstall Pi-hole from your system
|
||||||
status Display the running status of Pi-hole subsystems
|
status Display the running status of Pi-hole subsystems
|
||||||
enable Enable Pi-hole subsystems
|
enable Enable Pi-hole subsystems
|
||||||
Add '-h' for more info on enable usage
|
|
||||||
disable Disable Pi-hole subsystems
|
disable Disable Pi-hole subsystems
|
||||||
Add '-h' for more info on disable usage
|
Add '-h' for more info on disable usage
|
||||||
reloaddns Update the lists and flush the cache without restarting the DNS server
|
restartdns Restart Pi-hole subsystems
|
||||||
reloadlists Update the lists WITHOUT flushing the cache or restarting the DNS server
|
checkout Switch Pi-hole subsystems to a different Github branch
|
||||||
checkout Switch Pi-hole subsystems to a different GitHub branch
|
|
||||||
Add '-h' for more info on checkout usage
|
Add '-h' for more info on checkout usage
|
||||||
networkflush Flush information stored in Pi-hole's network tables
|
arpflush Flush information stored in Pi-hole's network tables";
|
||||||
Add '--arp' to additionally flush the ARP table
|
|
||||||
logrotate Rotate Pi-hole's log files
|
|
||||||
Add 'quiet' to suppress output messages";
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,77 +417,47 @@ if [[ $# = 0 ]]; then
|
|||||||
helpFunc
|
helpFunc
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# functions that do not require sudo power
|
|
||||||
need_root=
|
|
||||||
case "${1}" in
|
case "${1}" in
|
||||||
"-h" | "help" | "--help" ) helpFunc;;
|
"-h" | "help" | "--help" ) helpFunc;;
|
||||||
"-v" | "version" ) versionFunc;;
|
|
||||||
"-c" | "chronometer" ) chronometerFunc "$@";;
|
|
||||||
"-q" | "query" ) queryFunc "$@";;
|
|
||||||
"status" ) statusFunc "$2";;
|
|
||||||
"tricorder" ) tricorderFunc;;
|
|
||||||
"allow" | "allowlist" ) listFunc "$@";;
|
|
||||||
"deny" | "denylist" ) listFunc "$@";;
|
|
||||||
"--wild" | "wildcard" ) listFunc "$@";;
|
|
||||||
"--regex" | "regex" ) listFunc "$@";;
|
|
||||||
"--allow-regex" | "allow-regex" ) listFunc "$@";;
|
|
||||||
"--allow-wild" | "allow-wild" ) listFunc "$@";;
|
|
||||||
"enable" ) piholeEnable true "$2";;
|
|
||||||
"disable" ) piholeEnable false "$2";;
|
|
||||||
"api" ) shift; apiFunc "$@"; exit 0;;
|
|
||||||
|
|
||||||
# we need to add all arguments that require sudo power to not trigger the * argument
|
|
||||||
"-f" | "flush" ) need_root=true;;
|
|
||||||
"-up" | "updatePihole" ) need_root=true;;
|
|
||||||
"-r" | "repair" ) need_root=true;;
|
|
||||||
"-l" | "logging" ) need_root=true;;
|
|
||||||
"uninstall" ) need_root=true;;
|
|
||||||
"-d" | "debug" ) need_root=true;;
|
|
||||||
"-g" | "updateGravity" ) need_root=true;;
|
|
||||||
"reloaddns" ) need_root=true;;
|
|
||||||
"reloadlists" ) need_root=true;;
|
|
||||||
"setpassword" ) need_root=true;;
|
|
||||||
"checkout" ) need_root=true;;
|
|
||||||
"updatechecker" ) need_root=true;;
|
|
||||||
"arpflush" ) need_root=true;; # Deprecated, use networkflush instead
|
|
||||||
"networkflush" ) need_root=true;;
|
|
||||||
"-t" | "tail" ) need_root=true;;
|
|
||||||
"logrotate" ) need_root=true;;
|
|
||||||
* ) helpFunc;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# In the case of alpine running in a container, the USER variable appears to be blank
|
# Must be root to use this tool
|
||||||
# which prevents the next trap from working correctly. Set it by running whoami
|
if [[ ! $EUID -eq 0 ]];then
|
||||||
if [[ -z ${USER} ]]; then
|
if [[ -x "$(command -v sudo)" ]]; then
|
||||||
USER=$(whoami)
|
exec sudo bash "$0" "$@"
|
||||||
fi
|
exit $?
|
||||||
|
else
|
||||||
# Check if the current user is not root and if the command
|
echo -e " ${CROSS} sudo is needed to run pihole commands. Please run this script as root or install sudo."
|
||||||
# requires root. If so, exit with an error message.
|
exit 1
|
||||||
# Add an exception for the user "pihole" to allow the webserver running gravity
|
fi
|
||||||
if [[ ( $EUID -ne 0 && ${USER} != "pihole" ) && -n "${need_root}" ]]; then
|
|
||||||
echo -e " ${CROSS} This Pi-hole command requires root privileges, try:"
|
|
||||||
echo -e " ${COL_GREEN}sudo pihole $*${COL_NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Handle redirecting to specific functions based on arguments
|
# Handle redirecting to specific functions based on arguments
|
||||||
case "${1}" in
|
case "${1}" in
|
||||||
"-d" | "debug" ) debugFunc "$@";;
|
"-w" | "whitelist" ) listFunc "$@";;
|
||||||
"-f" | "flush" ) flushFunc "$@";;
|
"-b" | "blacklist" ) listFunc "$@";;
|
||||||
"-up" | "updatePihole" ) updatePiholeFunc "$@";;
|
"--wild" | "wildcard" ) listFunc "$@";;
|
||||||
"-r" | "repair" ) repairPiholeFunc "$@";;
|
"--regex" | "regex" ) listFunc "$@";;
|
||||||
"-g" | "updateGravity" ) updateGravityFunc "$@";;
|
"-d" | "debug" ) debugFunc "$@";;
|
||||||
"-l" | "logging" ) piholeLogging "$@";;
|
"-f" | "flush" ) flushFunc "$@";;
|
||||||
"uninstall" ) uninstallFunc;;
|
"-up" | "updatePihole" ) updatePiholeFunc "$@";;
|
||||||
"reloaddns" ) reloadDNS "reload";;
|
"-r" | "reconfigure" ) reconfigurePiholeFunc;;
|
||||||
"reloadlists" ) reloadDNS "reload-lists";;
|
"-g" | "updateGravity" ) updateGravityFunc "$@";;
|
||||||
"setpassword" ) SetWebPassword "$@";;
|
"-c" | "chronometer" ) chronometerFunc "$@";;
|
||||||
"checkout" ) piholeCheckoutFunc "$@";;
|
"-h" | "help" ) helpFunc;;
|
||||||
"updatechecker" ) shift; updateCheckFunc "$@";;
|
"-v" | "version" ) versionFunc "$@";;
|
||||||
"arpflush" ) arpFunc "$@";; # Deprecated, use networkflush instead
|
"-q" | "query" ) queryFunc "$@";;
|
||||||
"networkflush" ) networkFlush "$@";;
|
"-l" | "logging" ) piholeLogging "$@";;
|
||||||
"-t" | "tail" ) tailFunc "$2";;
|
"uninstall" ) uninstallFunc;;
|
||||||
"logrotate" ) logrotateFunc "$@";;
|
"enable" ) piholeEnable 1;;
|
||||||
* ) helpFunc;;
|
"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
|
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
|
||||||
6
setup.py
Normal file
6
setup.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
setup_requires=['pytest-runner'],
|
||||||
|
tests_require=['pytest'],
|
||||||
|
)
|
||||||
@@ -7,19 +7,19 @@ From command line all you need to do is:
|
|||||||
- `pip install tox`
|
- `pip install tox`
|
||||||
- `tox`
|
- `tox`
|
||||||
|
|
||||||
Tox handles setting up a virtual environment for python dependencies, installing dependencies, building the docker images used by tests, and finally running tests. It's an easy way to have travis-ci like build behavior locally.
|
Tox handles setting up a virtual environment for python dependancies, installing dependancies, building the docker images used by tests, and finally running tests. It's an easy way to have travis-ci like build behavior locally.
|
||||||
|
|
||||||
## Alternative py.test method of running tests
|
## Alternative py.test method of running tests
|
||||||
|
|
||||||
You're responsible for setting up your virtual env and dependencies in this situation.
|
You're responsible for setting up your virtual env and dependancies in this situation.
|
||||||
|
|
||||||
```
|
```
|
||||||
py.test -vv -n auto -m "build_stage"
|
py.test -vv -n auto -m "build_stage"
|
||||||
py.test -vv -n auto -m "not build_stage"
|
py.test -vv -n auto -m "not build_stage"
|
||||||
```
|
```
|
||||||
|
|
||||||
The build_stage tests have to run first to create the docker images, followed by the actual tests which utilize said images. Unless you're changing your dockerfiles you shouldn't have to run the build_stage every time - but it's a good idea to rebuild at least once a day in case the base Docker images or packages change.
|
The build_stage tests have to run first to create the docker images, followed by the actual tests which utilize said images. Unless you're changing your dockerfiles you shouldn't have to run the build_stage every time - but it's a good idea to rebuild at least once a day in case the base Docker images or packages change.
|
||||||
|
|
||||||
# How do I debug python?
|
# How do I debug python?
|
||||||
|
|
||||||
Highly recommended: Setup PyCharm on a **Docker enabled** machine. Having a python debugger like PyCharm changes your life if you've never used it :)
|
Highly recommended: Setup PyCharm on a **Docker enabled** machine. Having a python debugger like PyCharm changes your life if you've never used it :)
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
FROM alpine:3.21
|
|
||||||
|
|
||||||
ENV GITDIR=/etc/.pihole
|
|
||||||
ENV SCRIPTDIR=/opt/pihole
|
|
||||||
RUN sed -i 's/#\(.*\/community\)/\1/' /etc/apk/repositories
|
|
||||||
RUN apk --no-cache add bash coreutils curl git jq openrc shadow
|
|
||||||
|
|
||||||
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
|
||||||
ADD . $GITDIR
|
|
||||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $GITDIR/advanced/Scripts/COL_TABLE $SCRIPTDIR/
|
|
||||||
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
|
||||||
|
|
||||||
RUN true && \
|
|
||||||
chmod +x $SCRIPTDIR/*
|
|
||||||
|
|
||||||
ENV SKIP_INSTALL=true
|
|
||||||
|
|
||||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
FROM alpine:3.22
|
|
||||||
|
|
||||||
ENV GITDIR=/etc/.pihole
|
|
||||||
ENV SCRIPTDIR=/opt/pihole
|
|
||||||
RUN sed -i 's/#\(.*\/community\)/\1/' /etc/apk/repositories
|
|
||||||
RUN apk --no-cache add bash coreutils curl git jq openrc shadow
|
|
||||||
|
|
||||||
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
|
||||||
ADD . $GITDIR
|
|
||||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $GITDIR/advanced/Scripts/COL_TABLE $SCRIPTDIR/
|
|
||||||
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
|
||||||
|
|
||||||
RUN true && \
|
|
||||||
chmod +x $SCRIPTDIR/*
|
|
||||||
|
|
||||||
ENV SKIP_INSTALL=true
|
|
||||||
|
|
||||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user