Compare commits

..

30 Commits

Author SHA1 Message Date
Promofaux
84b54065ff rebase on development branch 2016-05-13 11:13:47 +01:00
Promofaux
f8edc810ff Copy some scripts from basic_install.sh. Add todo list comments. 2016-05-13 11:12:19 +01:00
Promofaux
c9b461a2f8 Flesh out updateDependencies. Add in root check. 2016-05-13 11:12:19 +01:00
Promofaux
e60490b4ed ground work on secondary update script 2016-05-13 11:12:19 +01:00
Promofaux
0ba6e59888 Call secondary update script after pull 2016-05-13 11:12:19 +01:00
Promofaux
0dd5970f49 Fix typo. Add secondary update script 2016-05-13 11:12:19 +01:00
Promofaux
f73360e791 add secondary update script. This is where the files will be distributed from once repo is up to date 2016-05-13 11:12:19 +01:00
Promofaux
0d5600c21d disable cron job (for now) to stop auto updates 2016-05-13 11:12:19 +01:00
Promofaux
c78c619cfb remove updatepihole 2016-05-13 11:12:19 +01:00
Promofaux
6469586a67 add updatePihole.sh to install script 2016-05-13 11:12:19 +01:00
Promofaux
42614f6a7a add pihole update script to 'pihole' command 2016-05-13 11:12:19 +01:00
Promofaux
aac7fa9c14 rename to updatePihole.sh 2016-05-13 11:10:04 +01:00
jacobsalmela
4b1633eac4 run at a different time than gravity update 2016-05-13 11:10:04 +01:00
jacobsalmela
86d7eada79 cron to update pi-hole
This checks once a week if core Pi-hole needs updating.
2016-05-13 11:10:04 +01:00
jacobsalmela
a70c3bac61 add update mechanism
This is some nice code found on stack overflow that I have been using
for a while that seems very reliable.  I just commented out a few
things since we really only want to check if it needs an update or if
it is already up to date.
2016-05-13 11:10:04 +01:00
Promofaux
67834062bc Copy some scripts from basic_install.sh. Add todo list comments. 2016-04-28 21:40:25 +01:00
Promofaux
5b0e73c9f3 Flesh out updateDependencies. Add in root check. 2016-04-28 21:32:24 +01:00
Promofaux
f671eef3f0 ground work on secondary update script 2016-04-08 23:43:31 +01:00
Promofaux
5ab54012d5 Call secondary update script after pull 2016-04-08 23:43:22 +01:00
Promofaux
a04b7c4e99 Fix typo. Add secondary update script 2016-04-08 23:42:34 +01:00
Promofaux
e4ce5e3601 add secondary update script. This is where the files will be distributed from once repo is up to date 2016-04-08 23:31:15 +01:00
Promofaux
06f1aea319 disable cron job (for now) to stop auto updates 2016-04-08 23:17:37 +01:00
Promofaux
2ab6746d53 remove updatepihole 2016-04-08 23:16:38 +01:00
Promofaux
253dfdf084 add updatePihole.sh to install script 2016-04-08 23:15:18 +01:00
Promofaux
cec727be9d add pihole update script to 'pihole' command 2016-04-08 23:13:13 +01:00
Promofaux
1d9531ef70 Merge branch 'development' into update-mechanism 2016-04-08 23:10:21 +01:00
Promofaux
fbc400c67e rename to updatePihole.sh 2016-04-08 23:09:12 +01:00
jacobsalmela
0e59cf0fd1 run at a different time than gravity update 2016-03-18 20:11:34 -05:00
jacobsalmela
96bacc372a cron to update pi-hole
This checks once a week if core Pi-hole needs updating.
2016-03-18 18:02:17 -05:00
jacobsalmela
6daf80ef56 add update mechanism
This is some nice code found on stack overflow that I have been using
for a while that seems very reliable.  I just commented out a few
things since we really only want to check if it needs an update or if
it is already up to date.
2016-03-18 18:01:51 -05:00
116 changed files with 3773 additions and 10622 deletions

View File

@@ -1,4 +0,0 @@
doubleclick
wan
nwe
padd

View File

@@ -1,20 +0,0 @@
# EditorConfig is awesome: https://editorconfig.org/
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = tab
tab_width = 4
charset = utf-8
trim_trailing_whitespace = true
[*.yml]
tab_width = 2
[*.md]
tab_width = 2

38
.gitattributes vendored
View File

@@ -1,38 +0,0 @@
# FROM https://github.com/libgit2/libgit2sharp
# Text files that should be normalized to LF in odb.
*.cs text diff=csharp
*.config text
*.sln text
*.csproj text
*.md text
*.sh text
*.ps1 text
*.cmd text
*.bat text
*.markdown text
*.msbuild text
Lib/* binary
GitHub.Tests.Integration/Resources/* binary
# Binary files that should not be normalized or diffed
*.png binary
*.jpg binary
*.gif binary
*.pfx binary
*.snk binary
*.dll binary
*.exe binary
*.lib binary
*.exp binary
*.pdb binary
*.sdf binary
*.7z binary
# Catch all for anything we forgot. Add rules if you get CRLF -> LF warnings.
* text eol=lf

5
.github/CODEOWNERS vendored
View File

@@ -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

7
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,7 @@
##### Expected Behaviour:
##### Actual Behaviour:
##### Steps to reproduce this issue:

11
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,11 @@
Fixes #[issue number] .
Changes proposed in this pull request:
-
-
-
@pi-hole/gravity

2
.github/dco.yml vendored
View File

@@ -1,2 +0,0 @@
require:
members: false

View File

@@ -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
View File

@@ -1,8 +0,0 @@
changelog:
exclude:
labels:
- internal
- dependencies
authors:
- dependabot
- github-actions

View File

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

View File

@@ -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@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."

View File

@@ -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@v9.1.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@v4.2.2
- name: Remove 'stale' label
run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -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@v9.1.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.'

View File

@@ -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@v4.2.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 }}

View File

@@ -1,95 +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@v4.2.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@v5
with:
severity: warning
display-engine: sarif-fmt
- name: Spell-Checking
uses: codespell-project/actions-codespell@master
with:
ignore_words_file: .codespellignore
- name: Get editorconfig-checker
uses: editorconfig-checker/action-editorconfig-checker@main # tag v1.0.0 is really out of date
- name: Run editorconfig-checker
run: editorconfig-checker
- name: Check python code formatting with black
uses: psf/black@stable
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,
ubuntu_20,
ubuntu_22,
ubuntu_24,
centos_9,
centos_10,
fedora_40,
fedora_41,
fedora_42,
]
env:
DISTRO: ${{matrix.distro}}
steps:
- name: Checkout repository
uses: actions/checkout@v4.2.2
- name: Set up Python
uses: actions/setup-python@v5.6.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

14
.gitignore vendored
View File

@@ -1,15 +1 @@
.DS_Store
*.pyc
*.swp
__pycache__
.cache
.pytest_cache
.tox
.eggs
*.egg-info
.idea/
*.iml
.vscode/
.venv/
.fleet/
.cache/

View File

@@ -1,2 +0,0 @@
external-sources=true # allow shellcheck to read external sources
disable=SC3043 #disable SC3043: In POSIX sh, local is undefined.

View File

@@ -1,5 +1,8 @@
# Contributors Guide
This is a basic checklist for now, We will update it in the future.
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/)
* Fork the repo and create your new branch based on the `development` branch.
* Commit Unix line endings
* If you want, try to keep to the theme of black holes/gravity. This can add some fun to your submission.
* 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!)
* Be patient. We will review all submitted pull requests, but our focus is on stability.. please don't be offended if we reject your PR, or it appears we're doing nothing with it! We'll get around to it..

389
LICENSE
View File

@@ -1,146 +1,339 @@
Copyright (C) 2017 Pi-hole, LLC (https://pi-hole.net)
Pi-hole Core
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
This software is licensed under the European Union Public License (EUPL)
The license is available in the 22 official languages of the EU. The English version is included here.
Please see https://joinup.ec.europa.eu/community/eupl/og_page/eupl for official translations of the other languages.
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This license applies to the whole project EXCEPT:
Preamble
- any commits made to the master branch prior to the release of version 3.0
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
The licenses that existed prior to this change have remained intact.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
-------------------------------------------------------------
EUROPEAN UNION PUBLIC LICENCE v. 1.2
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
EUPL © the European Union 2007, 2016
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
This European Union Public Licence (the EUPL) applies to the Work (as defined below) which is provided under the terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such use is covered by a right of the copyright holder of the Work).
The Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following notice immediately following the copyright notice for the Work:
Licensed under the EUPL
or has expressed by any other means his willingness to license under the EUPL.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
1. Definitions
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
In this Licence, the following terms have the following meaning:
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
- The Licence: this Licence.
- The Original Work: the work or software distributed or communicated by the Licensor under this Licence, available as Source Code and also as Executable Code as the case may be.
- Derivative Works: the works or software that could be created by the Licensee, based upon the Original Work or modifications thereof. This Licence does not define the extent of modification or dependence on the Original Work required in order to classify a work as a Derivative Work; this extent is determined by copyright law applicable in the country mentioned in Article 15.
- The Work: the Original Work or its Derivative Works.
- The Source Code: the human-readable form of the Work which is the most convenient for people to study and modify.
- The Executable Code: any code which has generally been compiled and which is meant to be interpreted by a computer as a program.
- The Licensor: the natural or legal person that distributes or communicates the Work under the Licence.
- Contributor(s): any natural or legal person who modifies the Work under the Licence, or otherwise contributes to the creation of a Derivative Work.
- The Licensee or You: any natural or legal person who makes any usage of the Work under the terms of the Licence.
- Distribution or Communication: any act of selling, giving, lending, renting, distributing, communicating, transmitting, or otherwise making available, online or offline, copies of the Work or providing access to its essential functionalities at the disposal of any other natural or legal person.
The precise terms and conditions for copying, distribution and
modification follow.
2. Scope of the rights granted by the Licence
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, sublicensable licence to do the following, for the duration of copyright vested in the Original Work:
- use the Work in any circumstance and for all usage,
- reproduce the Work,
- modify the Work, and make Derivative Works based upon the Work,
- communicate to the public, including the right to make available or display the Work or copies thereof to the public and perform publicly, as the case may be, the Work,
- distribute the Work or copies thereof,
- lend and rent the Work or copies thereof,
- sublicense rights in the Work or copies thereof.
Those rights can be exercised on any media, supports and formats, whether now known or later invented, as far as the applicable law permits so.
In the countries where moral rights apply, the Licensor waives his right to exercise his moral right to the extent allowed by law in order to make effective the licence of the economic rights here above listed.
The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to any patents held by the Licensor, to the extent necessary to make use of the rights granted on the Work under this Licence.
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
3. Communication of the Source Code
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to distribute or communicate the Work.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
4. Limitations on copyright
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the exclusive rights of the rights owners in the Work, of the exhaustion of those rights or of other applicable limitations thereto.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
5. Obligations of the Licensee
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
The grant of the rights mentioned above is subject to some restrictions and obligations imposed on the Licensee. Those obligations are the following:
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
Attribution right: The Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the Licence with every copy of the Work he/she distributes or communicates. The Licensee must cause any Derivative Work to carry prominent notices stating that the Work has been modified and the date of modification.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
Copyleft clause: If the Licensee distributes or communicates copies of the Original Works or Derivative Works, this Distribution or Communication will be done under the terms of this Licence or of a later version of this Licence unless the Original Work is expressly distributed only under this version of the Licence - for example by communicating EUPL v. 1.2 only. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the Work or Derivative Work that alter or restrict the terms of the Licence.
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Compatibility clause: If the Licensee Distributes or Communicates Derivative Works or copies thereof based upon both the Work and another work licensed under a Compatible Licence, this Distribution or Communication can be done under the terms of this Compatible Licence. For the sake of this clause, Compatible Licence refers to the licences listed in the appendix attached to this Licence. Should the Licensee's obligations under the Compatible Licence conflict with his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
Provision of Source Code: When distributing or communicating copies of the Work, the Licensee will provide a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available for as long as the Licensee continues to distribute or communicate the Work.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
Legal Protection: This Licence does not grant permission to use the trade names, trademarks, service marks, or names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the copyright notice.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
6. Chain of Authorship
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
The original Licensor warrants that the copyright in the Original Work granted hereunder is owned by him/her or licensed to him/her and that he/she has the power and authority to grant the Licence.
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
Each Contributor warrants that the copyright in the modifications he/she brings to the Work are owned by him/her or licensed to him/her and that he/she has the power and authority to grant the Licence.
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
Each time You accept the Licence, the original Licensor and subsequent Contributors grant You a licence to their contributions to the Work, under the terms of this Licence.
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
7. Disclaimer of Warranty
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
The Work is a work in progress, which is continuously improved by numerous Contributors. It is not a finished work and may therefore contain defects or bugs inherent to this type of development.
For the above reason, the Work is provided under the Licence on an as is basis and without warranties of any kind concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this Licence.
This disclaimer of warranty is an essential part of the Licence and a condition for the grant of any rights to the Work.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
8. Disclaimer of Liability
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
Except in the cases of wilful misconduct or damages directly caused to natural persons, the Licensor will in no event be liable for any direct or indirect, material or moral, damages of any kind, arising out of the Licence or of the use of the Work, including without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, loss of data or any commercial damage, even if the Licensor has been advised of the possibility of such damage. However, the Licensor will be liable under statutory product liability laws as far such laws apply to the Work.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
9. Additional agreements
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
While distributing the Work, You may choose to conclude an additional agreement, defining obligations or services consistent with this Licence. However, if accepting obligations, You may act only on your own behalf and on your sole responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by the fact You have accepted any warranty or additional liability.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
10. Acceptance of the Licence
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
The provisions of this Licence can be accepted by clicking on an icon I agree placed under the bottom of a window displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms and conditions.
Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution or Communication by You of the Work or copies thereof.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
11. Information to the public
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
In case of any Distribution or Communication of the Work by means of electronic communication by You (for example, by offering to download the Work from a remote location) the distribution channel or media (for example, a website) must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence and the way it may be accessible, concluded, stored and reproduced by the Licensee.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
12. Termination of the Licence
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
The Licence and the rights granted hereunder will terminate automatically upon any breach by the Licensee of the terms of the Licence.
Such a termination will not terminate the licences of any person who has received the Work from the Licensee under the Licence, provided such persons remain in full compliance with the Licence.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
13. Miscellaneous
NO WARRANTY
Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the Work.
If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or enforceability of the Licence as a whole. Such provision will be construed or reformed so as necessary to make it valid and enforceable.
The European Commission may publish other linguistic versions or new versions of this Licence or updated versions of the Appendix, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence. New versions of the Licence will be published with a unique version number.
All linguistic versions of this Licence, approved by the European Commission, have identical value. Parties can take advantage of the linguistic version of their choice.
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
14. Jurisdiction
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
Without prejudice to specific agreement between parties,
- any litigation resulting from the interpretation of this License, arising between the European Union institutions, bodies, offices or agencies, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice of the European Union, as laid down in article 272 of the Treaty on the Functioning of the European Union,
- any litigation arising between other parties and resulting from the interpretation of this License, will be subject to the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business.
END OF TERMS AND CONDITIONS
15. Applicable Law
How to Apply These Terms to Your New Programs
Without prejudice to specific agreement between parties,
- this Licence shall be governed by the law of the European Union Member State where the Licensor has his seat, resides or has his registered office,
- this licence shall be governed by Belgian law if the Licensor has no seat, residence or registered office inside a European Union Member State.
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
===
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Appendix
{description}
Copyright (C) {year} {fullname}
Compatible Licences according to Article 5 EUPL are:
- GNU General Public License (GPL) v. 2, v. 3
- GNU Affero General Public License (AGPL) v. 3
- Open Software License (OSL) v. 2.1, v. 3.0
- Eclipse Public License (EPL) v. 1.0
- CeCILL v. 2.0, v. 2.1
- Mozilla Public Licence (MPL) v. 2
- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for works other than software
- European Union Public Licence (EUPL) v. 1.1, v. 1.2
- Québec Free and Open-Source Licence - Reciprocity (LiLiQ-R) or Strong Reciprocity (LiLiQ-R+)
- The European Commission may update this Appendix to later versions of the above licences without producing a new version of the EUPL, as long as they provide the rights granted in Article 2 of this Licence and protect the covered Source Code from exclusive appropriation.
- All other changes or additions to this Appendix require the production of a new EUPL version.
This program 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

213
README.md
View File

@@ -1,170 +1,111 @@
<!-- markdownlint-configure-file { "MD004": { "style": "consistent" } } -->
<!-- markdownlint-disable MD033 -->
#
# Automated Install
##### Designed For Raspberry Pi A+, B, B+, 2, Zero, and 3B (with an Ethernet/Wi-Fi adapter) (Works on most Debian distributions!)
<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">
<br>
<strong>Network-wide ad blocking via your own Linux hardware</strong>
</p>
<!-- markdownlint-enable MD033 -->
[![Join the chat at https://gitter.im/pi-hole/pi-hole](https://badges.gitter.im/pi-hole/pi-hole.svg)](https://gitter.im/pi-hole/pi-hole?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
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.
1. Install Raspbian
- **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
- **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/)
- **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
- **Versatile**: can optionally function as a [DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026), ensuring _all_ your devices are protected automatically
- **Scalable**: [capable of handling hundreds of millions of queries](https://pi-hole.net/2017/05/24/how-much-traffic-can-pi-hole-handle/) when installed on server-grade hardware
- **Modern**: blocks ads over both IPv4 and IPv6
- **Free**: open source software that helps ensure _you_ are the sole person in control of your privacy
2. Run the command below
-----
### ```curl -L https://install.pi-hole.net | bash```
## One-Step Automated Install
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
#### Alternative Semi-Automated install ####
```
## 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:
### Method 1: Clone our repository and run
```bash
git clone --depth 1 https://github.com/pi-hole/pi-hole.git Pi-hole
cd "Pi-hole/automated install/"
sudo bash basic-install.sh
```
### Method 2: Manually download the installer and run
```bash
wget -O basic-install.sh https://install.pi-hole.net
sudo bash basic-install.sh
chmod +x basic-install.sh
./basic-install.sh
```
### Method 3: Using Docker to deploy Pi-hole
Once installed, [configure your router to have **DHCP clients use the Pi as their DNS server**](http://pi-hole.net/faq/can-i-set-the-pi-hole-to-be-the-dns-server-at-my-router-so-i-dont-have-to-change-settings-for-my-devices/) and then any device that connects to your network will have ads blocked without any further configuration. Alternatively, you can manually set each device to [use the Raspberry Pi as its DNS server](http://pi-hole.net/faq/how-do-i-use-the-pi-hole-as-my-dns-server/).
Please refer to the [Pi-hole docker repo](https://github.com/pi-hole/docker-pi-hole) to use the Official Docker Images.
## Pi-hole Is Free, But Powered By Your Donations
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif "Free, but powered by donations")](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY "Donate")
## [Post-install: Make your network take advantage of Pi-hole](https://docs.pi-hole.net/main/post-install/)
## Catch us out on the net:
Twitter: [@The_Pi_Hole](https://twitter.com/The_Pi_Hole)
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.
reddit: [/r/pihole](https://www.reddit.com/r/pihole/)
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).
## How Does It Work?
**Watch the 60-second video below to get a quick overview**
As a last resort, you can manually set each device to use Pi-hole as their DNS server.
[![Pi-hole exlplained](http://i.imgur.com/qNybJDX.png)](https://vimeo.com/135965232)
-----
## Pi-hole Projects
- [Pi-hole stats in your Mac's menu bar](https://getbitbar.com/plugins/Network/pi-hole.1m.py)
- [Get LED alerts for each blocked ad](http://www.stinebaugh.info/get-led-alerts-for-each-blocked-ad-using-pi-hole/)
- [Pi-hole on Ubuntu 14.04 on VirtualBox](http://hbalagtas.blogspot.com/2016/02/adblocking-with-pi-hole-and-ubuntu-1404.html)
- [x86 Docker container that runs Pi-hole](https://hub.docker.com/r/diginc/pi-hole/)
- [Splunk: Pi-hole Visualizser](https://splunkbase.splunk.com/app/3023/)
- [Pi-hole Chrome extension](https://chrome.google.com/webstore/detail/pi-hole-list-editor/hlnoeoejkllgkjbnnnhfolapllcnaglh) ([open source](https://github.com/packtloss/pihole-extension))
- [Go Bananas for CHiP-hole ad blocking](https://www.hackster.io/jacobsalmela/chip-hole-network-wide-ad-blocker-98e037)
- [Sky-Hole](http://dlaa.me/blog/post/skyhole)
- [Pi-hole in the Cloud!](http://blog.codybunch.com/2015/07/28/Pi-Hole-in-the-cloud/)
- [unRaid-hole](https://github.com/spants/unraidtemplates/blob/master/Spants/unRaid-hole.xml#L13)--[Repo and more info](http://lime-technology.com/forum/index.php?PHPSESSID=c0eae3e5ef7e521f7866034a3336489d&topic=38486.0)
- [Pi-hole on/off button](http://thetimmy.silvernight.org/pages/endisbutton/)
- [Minibian Pi-hole](http://munkjensen.net/wiki/index.php/See_my_Pi-Hole#Minibian_Pi-hole)
## Pi-hole is free but powered by your support
## Coverage
- [TekThing: 5 fun, easy projects for a Raspberry Pi](https://youtu.be/QwrKlyC2kdM?t=1m42s)
- [Pi-hole on Adafruit's blog](https://blog.adafruit.com/2016/03/04/pi-hole-is-a-black-hole-for-internet-ads-piday-raspberrypi-raspberry_pi/)
- [The Defrag Show - MSDN/Channel 9](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)
- [MacObserver Podcast 585](http://www.macobserver.com/tmo/podcast/macgeekgab-585)
- [Medium: Block All Ads For $53](https://medium.com/@robleathern/block-ads-on-all-home-devices-for-53-18-a5f1ec139693#.gj1xpgr5d)
- [MakeUseOf: Adblock Everywhere, The Pi-hole Way](http://www.makeuseof.com/tag/adblock-everywhere-raspberry-pi-hole-way/)
- [Lifehacker: Turn Your Pi Into An Ad Blocker With A Single Command](http://lifehacker.com/turn-a-raspberry-pi-into-an-ad-blocker-with-a-single-co-1686093533)!
- [Pi-hole on TekThing](https://youtu.be/8Co59HU2gY0?t=2m)
- [Pi-hole on Security Now! Podcast](http://www.youtube.com/watch?v=p7-osq_y8i8&t=100m26s)
- [Foolish Tech Show](https://youtu.be/bYyena0I9yc?t=2m4s)
- [Pi-hole on Ubuntu](http://www.boyter.org/2015/12/pi-hole-ubuntu-14-04/)
- [Catchpoint: iOS 9 Ad Blocking](http://blog.catchpoint.com/2015/09/14/ad-blocking-apple/)
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.
## Partnering With Optimal.com
Make no mistake: **your support is absolutely vital to help keep us innovating!**
Pi-hole will be teaming up with [Rob Leathern's subscription service to avoid ads](https://medium.com/@robleathern/block-ads-on-all-home-devices-for-53-18-a5f1ec139693#.gj1xpgr5d). This service is unique and will help content-creators and publishers [still make money from visitors who are using an ad ablocker](http://techcrunch.com/2015/12/17/the-new-optimal/).
### [Donations](https://pi-hole.net/donate)
## Technical Details
Donating using our Sponsor Button is **extremely helpful** in offsetting a portion of our monthly expenses:
The Pi-hole is an **advertising-aware DNS/Web server**. If an ad domain is queried, a small Web page or GIF is delivered in place of the advertisement. You can also [replace ads with any image you want](http://pi-hole.net/faq/is-it-possible-to-change-the-blank-page-that-takes-place-of-the-ads-to-something-else/) since it is just a simple Webpage taking place of the ads.
### Alternative support
A more detailed explanation of the installation can be found [here](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0).
If you'd rather not donate (_which is okay!_), there are other ways you can help support us:
## Gravity
The [gravity.sh](https://github.com/pi-hole/pi-hole/blob/master/gravity.sh) does most of the magic. The script pulls in ad domains from many sources and compiles them into a single list of [over 1.6 million entries](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0) (if you decide to use the [mahakala list](https://github.com/pi-hole/pi-hole/commit/963eacfe0537a7abddf30441c754c67ca1e40965)).
- [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_
- [Amazon US](https://www.amazon.com/exec/obidos/redirect-home/pihole09-20) _affiliate link_
- Spreading the word about our software and how you have benefited from it
## Whitelist and blacklist
Domains can be whitelisted and blacklisted using two pre-installed scripts. See [the wiki page](https://github.com/pi-hole/pi-hole/wiki/Whitelisting-and-Blacklisting) for more details
### Contributing via GitHub
## Web Interface
The [Web interface](https://github.com/jacobsalmela/AdminLTE#pi-hole-admin-dashboard) will be installed automatically so you can view stats and change settings. You can find it at:
We welcome _everyone_ to contribute to issue reports, suggest new features, and create pull requests.
`http://192.168.1.x/admin/index.php`
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.
![Pi-hole Advanced Stats Dashboard](http://i.imgur.com/rTlLYPh.png)
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.
### API
-----
A basic read-only API can be accessed at `/admin/api.php`. It returns the following JSON:
```JSON
{
"domains_being_blocked": "136708",
"dns_queries_today": "18108",
"ads_blocked_today": "14648",
"ads_percentage_today": "80.89"
}
```
The same output can be acheived on the CLI by running `chronometer.sh -j`
## Getting in touch with us
![Web](http://i.imgur.com/m114SCn.png)
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.
## Real-time Statistics
**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.
You can view [real-time stats](http://pi-hole.net/faq/install-the-real-time-lcd-monitor-chronometer/) via `ssh` or on an [2.8" LCD screen](http://amzn.to/1P0q1Fj). This is accomplished via [`chronometer.sh`](https://github.com/pi-hole/pi-hole/blob/master/advanced/Scripts/chronometer.sh).
![Pi-hole LCD](http://i.imgur.com/nBEqycp.jpg)
- [Frequently Asked Questions](https://discourse.pi-hole.net/c/faqs)
- [Feature Requests](https://discourse.pi-hole.net/c/feature-requests?order=votes)
- [Reddit](https://www.reddit.com/r/pihole/)
- [Twitter](https://twitter.com/The_Pi_hole)
## Help
- See the [Wiki](https://github.com/pi-hole/pi-hole/wiki/Customization) entry for more details
- There is also an [FAQ section on pi-hole.net](http://pi-hole.net)
-----
## Breakdown of Features
### [Faster-than-light Engine](https://github.com/pi-hole/ftl)
[FTLDNS](https://github.com/pi-hole/ftl) is a lightweight, purpose-built daemon used to provide statistics needed for the Web Interface, and its API can be easily integrated into your own projects. As the name implies, FTLDNS does this all _very quickly_!
Some of the statistics you can integrate include:
- Total number of domains being blocked
- Total number of DNS queries today
- Total number of ads blocked today
- Percentage of ads blocked
- Unique domains
- Queries forwarded (to your chosen upstream DNS server)
- Queries cached
- Unique clients
Access the API 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:
- [Allowlisting, Denylisting (fka Whitelisting, Blacklisting), and Regex](https://docs.pi-hole.net/core/pihole-command/#allowlisting-denylisting-and-regex)
- [Debugging utility](https://docs.pi-hole.net/core/pihole-command/#debugger)
- [Viewing the live log file](https://docs.pi-hole.net/core/pihole-command/#tail)
- [Updating Ad Lists](https://docs.pi-hole.net/core/pihole-command/#gravity)
- [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
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!
Some notable features include:
- Mobile-friendly interface
- Password protection
- Detailed graphs and doughnut charts
- Top lists of domains and clients
- A filterable and sortable query log
- Long Term Statistics to view data over user-defined time ranges
- The ability to easily manage and configure Pi-hole features
- ... 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):
1. `http://pi.hole/admin/` (when using Pi-hole as your DNS server)
2. `http://<IP_ADDRESS_OF_YOUR_PI_HOLE>/admin/`
## Other Operating Systems
This script will work for other UNIX-like systems with some slight **modifications**. As long as you can install `dnsmasq` and a Webserver, it should work OK. The automated install is only for a clean install of a Debian based system, such as the Raspberry Pi.

53
adlists.default Normal file
View File

@@ -0,0 +1,53 @@
## Pi-hole ad-list default sources. Updated 21/02/2016 #########################
# #
# To make changes to this file: #
# 1. run `cp /etc/pihole/adlists.default /etc/pihole/adlists.list` #
# 2. run `nano /etc/pihole/adlists.list` #
# 3. Uncomment or comment any of the below lists #
# #
# Know of any other lists? Feel free to let us know about them, or add them #
# to this file! #
################################################################################
# The below list amalgamates several lists we used previously.
# See `https://github.com/StevenBlack/hosts` for details
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
# Other lists we consider safe:
http://adblock.gjtech.net/?format=unix-hosts
http://mirror1.malwaredomains.com/files/justdomains
http://sysctl.org/cameleon/hosts
https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist
https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt
# hosts-file.net list. Updated frequently, but has been known to block legitimate sites.
http://hosts-file.net/ad_servers.txt
# Mahakala list. Has been known to block legitimage domains including the entire .com range.
# Warning: Due to the sheer size of this list, the web admin console will be unresponsive.
#http://adblock.mahakala.is/
# ADZHOSTS list. Has been known to block legitimate domains
#http://optimate.dl.sourceforge.net/project/adzhosts/HOSTS.txt
# Windows 10 telemetry list
#https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/hostsBlockWindowsSpy.txt
# Securemecca.com list - Also blocks "adult" sites (pornography/gambling etc)
#http://securemecca.com/Downloads/hosts.txt
# Quidsup's tracker list
https://raw.githubusercontent.com/quidsup/notrack/master/trackers.txt
# Block the BBC News website Breaking News banner
#https://raw.githubusercontent.com/BreakingTheNews/BreakingTheNews.github.io/master/hosts
# Untested Lists:
#https://raw.githubusercontent.com/reek/anti-adblock-killer/master/anti-adblock-killer-filters.txt
#http://spam404bl.com/spam404scamlist.txt
#http://malwaredomains.lehigh.edu/files/domains.txt
# Following two lists should be used simultaneously: (readme https://github.com/notracking/hosts-blocklists/)
#https://raw.github.com/notracking/hosts-blocklists/master/hostnames.txt
#https://raw.github.com/notracking/hosts-blocklists/master/domains.txt

61
advanced/01-pihole.conf Normal file
View File

@@ -0,0 +1,61 @@
# 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
# dnsmasq config 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.
# If you want dnsmasq to read another file, as well as /etc/hosts, use
# this.
addn-hosts=/etc/pihole/gravity.list
# 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
# 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
# Add other name servers here, with domain specs if they are for
# non-public domains.
server=@DNS1@
server=@DNS2@
# 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.
interface=@INT@
# Or which to listen on by address (remember to include 127.0.0.1 if
# you use this.)
listen-address=127.0.0.1
# Set the cachesize here.
cache-size=10000
# For debugging purposes, log each DNS query as it passes through
# dnsmasq.
log-queries
log-facility=/var/log/pihole.log
# 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=300
# This allows it to continue functioning without being blocked by syslog, and allows syslog to use dnsmasq for DNS queries without risking deadlock
log-async

BIN
advanced/GIFs/25Bytes.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

BIN
advanced/GIFs/26Bytes.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 B

BIN
advanced/GIFs/37Bytes.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 B

BIN
advanced/GIFs/43Bytes.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

View File

@@ -1,35 +0,0 @@
#!/usr/bin/env sh
# shellcheck disable=SC2034 # Disable warning about unused variables
# 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
# If something MUST be emphasized, use both
COL_BOLD=''
COL_NC=''
COL_GRAY=''
COL_RED=''
COL_GREEN=''
COL_YELLOW=''
COL_BLUE=''
COL_PURPLE=''
COL_CYAN=''
else
# Provide empty variables for `set -u`
COL_BOLD=""
COL_NC=""
COL_GRAY=""
COL_RED=""
COL_GREEN=""
COL_YELLOW=""
COL_BLUE=""
COL_PURPLE=""
COL_CYAN=""
fi
TICK="[${COL_GREEN}✓${COL_NC}]"
CROSS="[${COL_RED}✗${COL_NC}]"
INFO="[i]"
QST="[?]"
OVER="\\r"

View File

@@ -1,365 +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
echo "Authentication failed. Please enter your Pi-hole password"
# 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
# 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 and sessionMessage from session response
validSession=$(echo "${sessionResponse}"| jq .session.valid 2>/dev/null)
SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid 2>/dev/null)
sessionMessage=$(echo "${sessionResponse}"| jq --raw-output .session.message 2>/dev/null)
# obtain the error message from the session response
sessionError=$(echo "${sessionResponse}"| jq --raw-output .error.message 2>/dev/null)
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
if command -v jq >/dev/null && echo "${data}" | jq . >/dev/null 2>&1; then
echo "${data}" | jq .
else
echo "${data}"
fi
# Delete the session
LogoutAPI "${verbosity}"
}

242
advanced/Scripts/blacklist.sh Executable file
View File

@@ -0,0 +1,242 @@
#!/usr/bin/env bash
# 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
# Blacklists domains
#
# 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.
#rootcheck
if [[ $EUID -eq 0 ]];then
echo "::: You are root."
else
echo "::: sudo will be used."
# Check if it is actually installed
# If it isn't, exit because the install cannot complete
if [[ $(dpkg-query -s sudo) ]];then
export SUDO="sudo"
else
echo "::: Please install sudo or run this script as root."
exit 1
fi
fi
if [[ $# = 0 ]]; then
helpFunc
fi
#globals
basename=pihole
piholeDir=/etc/$basename
adList=$piholeDir/gravity.list
blacklist=$piholeDir/blacklist.txt
reload=true
addmode=true
force=false
verbose=true
domList=()
domToRemoveList=()
piholeIPfile=/etc/pihole/piholeIP
piholeIPv6file=/etc/pihole/.useIPv6
if [[ -f $piholeIPfile ]];then
# If the file exists, it means it was exported from the installation script and we should use that value instead of detecting it in this script
piholeIP=$(cat $piholeIPfile)
#rm $piholeIPfile
else
# Otherwise, the IP address can be taken directly from the machine, which will happen when the script is run by the user and not the installation script
IPv4dev=$(ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++)if($i~/dev/)print $(i+1)}')
piholeIPCIDR=$(ip -o -f inet addr show dev "$IPv4dev" | awk '{print $4}' | awk 'END {print}')
piholeIP=${piholeIPCIDR%/*}
fi
modifyHost=false
# After setting defaults, check if there's local overrides
if [[ -r $piholeDir/pihole.conf ]];then
echo "::: Local calibration requested..."
. $piholeDir/pihole.conf
fi
if [[ -f $piholeIPv6file ]];then
# If the file exists, then the user previously chose to use IPv6 in the automated installer
piholeIPv6=$(ip -6 route get 2001:4860:4860::8888 | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "src") print $(i+1) }')
fi
function helpFunc()
{
echo "::: Immediately blacklists one or more domains in the hosts file"
echo ":::"
echo ":::"
echo "::: Usage: pihole -b domain1 [domain2 ...]"
echo "::: Options:"
echo "::: -d, --delmode Remove domains from the blacklist"
echo "::: -nr, --noreload Update blacklist without refreshing dnsmasq"
echo "::: -f, --force Force updating of the hosts files, even if there are no changes"
echo "::: -q, --quiet output is less verbose"
echo "::: -h, --help Show this help dialog"
echo "::: -l, --list Display your blacklisted domains"
exit 1
}
if [[ $# = 0 ]]; then
helpFunc
fi
function HandleOther(){
#check validity of domain
validDomain=$(echo "$1" | perl -ne'print if /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/')
if [ -z "$validDomain" ]; then
echo "::: $1 is not a valid argument or domain name"
else
domList=("${domList[@]}" $validDomain)
fi
}
function PopBlacklistFile(){
#check blacklist file exists, and if not, create it
if [[ ! -f $blacklist ]];then
touch $blacklist
fi
for dom in "${domList[@]}"; do
if "$addmode"; then
AddDomain "$dom"
else
RemoveDomain "$dom"
fi
done
}
function AddDomain(){
#| sed 's/\./\\./g'
bool=false
grep -Ex -q "$1" $blacklist || bool=true
if $bool; then
#domain not found in the blacklist file, add it!
if $verbose; then
echo -n "::: Adding $1 to blacklist file..."
fi
echo "$1" >> $blacklist
modifyHost=true
echo " done!"
else
if $verbose; then
echo "::: $1 already exists in $blacklist! No need to add"
fi
fi
}
function RemoveDomain(){
bool=false
grep -Ex -q "$1" $blacklist || bool=true
if $bool; then
#Domain is not in the blacklist file, no need to Remove
if $verbose; then
echo "::: $1 is NOT blacklisted! No need to remove"
fi
else
#Domain is in the blacklist file, add to a temporary array
if $verbose; then
echo "::: Un-blacklisting $dom..."
fi
domToRemoveList=("${domToRemoveList[@]}" $1)
modifyHost=true
fi
}
function ModifyHostFile(){
if $addmode; then
#add domains to the hosts file
if [[ -r $blacklist ]];then
numberOf=$(cat $blacklist | sed '/^\s*$/d' | wc -l)
plural=; [[ "$numberOf" != "1" ]] && plural=s
echo ":::"
echo -n "::: Modifying HOSTS file to blacklist $numberOf domain${plural}..."
if [[ -n $piholeIPv6 ]];then
cat $blacklist | awk -v ipv4addr="$piholeIP" -v ipv6addr="$piholeIPv6" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> $adList
else
cat $blacklist | awk -v ipv4addr="$piholeIP" '{sub(/\r$/,""); print ipv4addr" "$0}' >>$adList
fi
fi
else
echo ":::"
for dom in "${domToRemoveList[@]}"
do
#we need to remove the domains from the blacklist file and the host file
echo "::: $dom"
echo -n "::: removing from HOSTS file..."
echo "$dom" | sed 's/\./\\./g' | xargs -I {} perl -i -ne'print unless /[^.]'{}'(?!.)/;' $adList
echo " done!"
echo -n "::: removing from blackist.txt..."
echo "$dom" | sed 's/\./\\./g' | xargs -I {} perl -i -ne'print unless /'{}'(?!.)/;' $blacklist
echo " done!"
done
fi
}
function Reload() {
# Reload hosts file
echo ":::"
echo -n "::: Refresh lists in dnsmasq..."
dnsmasqPid=$(pidof dnsmasq)
if [[ $dnsmasqPid ]]; then
# service already running - reload config
$SUDO killall -s HUP dnsmasq
else
# service not running, start it up
$SUDO service dnsmasq start
fi
echo " done!"
}
function DisplayBlist() {
verbose=false
echo -e " Displaying Gravity Affected Domains \n"
count=1
while IFS= read -r AD
do
echo "${count}: $AD"
count=$((count+1))
done < "$blacklist"
}
###################################################
for var in "$@"
do
case "$var" in
"-nr"| "--noreload" ) reload=false;;
"-d" | "--delmode" ) addmode=false;;
"-f" | "--force" ) force=true;;
"-q" | "--quiet" ) verbose=false;;
"-h" | "--help" ) helpFunc;;
"-l" | "--list" ) DisplayBlist;;
* ) HandleOther "$var";;
esac
done
PopBlacklistFile
if $modifyHost || $force; then
ModifyHostFile
else
if $verbose; then
echo "::: No changes need to be made"
fi
exit 1
fi
if $reload; then
Reload
fi

148
advanced/Scripts/chronometer.sh Executable file
View File

@@ -0,0 +1,148 @@
#!/usr/bin/env bash
# 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
# Calculates stats and displays to an LCD
#
# 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.
#Functions##############################################################################################################
piLog="/var/log/pihole.log"
gravity="/etc/pihole/gravity.list"
today=$(date "+%b %e")
function CalcBlockedDomains(){
CheckIPv6
if [ -e "$gravity" ]; then
#Are we IPV6 or IPV4?
if [[ -n $piholeIPv6 ]];then
#We are IPV6
blockedDomainsTotal=$(wc -l /etc/pihole/gravity.list | awk '{print $1/2}')
else
#We are IPV4
blockedDomainsTotal=$(wc -l /etc/pihole/gravity.list | awk '{print $1}')
fi
else
blockedDomainsTotal="Err."
fi
}
function CalcQueriesToday(){
if [ -e "$piLog" ];then
queriesToday=$(cat "$piLog" | grep "$today" | awk '/query/ {print $6}' | wc -l)
else
queriesToday="Err."
fi
}
function CalcblockedToday(){
if [ -e "$piLog" ] && [ -e "$gravity" ];then
blockedToday=$(cat $piLog | awk '/\/etc\/pihole\/gravity.list/ && !/address/ {print $6}' | wc -l)
else
blockedToday="Err."
fi
}
function CalcPercentBlockedToday(){
if [ "$queriesToday" != "Err." ] && [ "$blockedToday" != "Err." ]; then
if [ "$queriesToday" != 0 ]; then #Fixes divide by zero error :)
#scale 2 rounds the number down, so we'll do scale 4 and then trim the last 2 zeros
percentBlockedToday=$(echo "scale=4; $blockedToday/$queriesToday*100" | bc)
percentBlockedToday=$(sed 's/.\{2\}$//' <<< "$percentBlockedToday")
else
percentBlockedToday=0
fi
fi
}
function CheckIPv6(){
piholeIPv6file="/etc/pihole/.useIPv6"
if [[ -f $piholeIPv6file ]];then
# If the file exists, then the user previously chose to use IPv6 in the automated installer
piholeIPv6=$(ip -6 route get 2001:4860:4860::8888 | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "src") print $(i+1) }')
fi
}
function outputJSON(){
CalcQueriesToday
CalcblockedToday
CalcPercentBlockedToday
CalcBlockedDomains
printf '{"domains_being_blocked":"%s","dns_queries_today":"%s","ads_blocked_today":"%s","ads_percentage_today":"%s"}\n' "$blockedDomainsTotal" "$queriesToday" "$blockedToday" "$percentBlockedToday"
}
function normalChrono(){
for (( ; ; ))
do
clear
# Displays a colorful Pi-hole logo
echo " ___ _ _ _"
echo "| _ (_)___| |_ ___| |___"
echo "| _/ |___| ' \/ _ \ / -_)"
echo "|_| |_| |_||_\___/_\___|"
echo ""
echo " $(ifconfig eth0 | awk '/inet addr/ {print $2}' | cut -d':' -f2)"
echo ""
uptime | cut -d' ' -f11-
#uptime -p #Doesn't work on all versions of uptime
uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}'
echo "-------------------------------"
# Uncomment to continually read the log file and display the current domain being blocked
#tail -f /var/log/pihole.log | awk '/\/etc\/pihole\/gravity.list/ {if ($7 != "address" && $7 != "name" && $7 != "/etc/pihole/gravity.list") print $7; else;}'
#uncomment next 4 lines to use original query count calculation
#today=$(date "+%b %e")
#todaysQueryCount=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ {print $7}' | wc -l)
#todaysQueryCountV4=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ && /\[A\]/ {print $7}' | wc -l)
#todaysQueryCountV6=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ && /\[AAAA\]/ {print $7}' | wc -l)
CalcQueriesToday
CalcblockedToday
CalcPercentBlockedToday
CalcBlockedDomains
echo "Blocking: $blockedDomainsTotal"
#below commented line does not add up to todaysQueryCount
#echo "Queries: $todaysQueryCountV4 / $todaysQueryCountV6"
echo "Queries: $queriesToday" #same total calculation as dashboard
echo "Pi-holed: $blockedToday ($percentBlockedToday%)"
sleep 5
done
}
function displayHelp(){
echo "::: Displays stats about your piHole!"
echo ":::"
echo "::: Usage: sudo pihole -c [optional:-j]"
echo "::: Note: If no option is passed, then stats are displayed on screen, updated every 5 seconds"
echo ":::"
echo "::: Options:"
echo "::: -j, --json output stats as JSON formatted string"
echo "::: -h, --help display this help text"
exit 1
}
if [[ $# = 0 ]]; then
normalChrono
fi
for var in "$@"
do
case "$var" in
"-j" | "--json" ) outputJSON;;
"-h" | "--help" ) displayHelp;;
* ) exit 1;;
esac
done

View File

@@ -1,153 +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.
#
# Updates gravity.db database
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
readonly scriptPath="/etc/.pihole/advanced/Scripts/database_migration/gravity"
upgrade_gravityDB(){
local database version
database="${1}"
# Exit early if the database does not exist (e.g. in CI tests)
if [[ ! -f "${database}" ]]; then
return
fi
# Get database version
version="$(pihole-FTL sqlite3 -ni "${database}" "SELECT \"value\" FROM \"info\" WHERE \"property\" = 'version';")"
if [[ "$version" == "1" ]]; then
# This migration script upgraded the gravity.db file by
# adding the domain_audit table. It is now a no-op
echo -e " ${INFO} Upgrading gravity database from version 1 to 2"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/1_to_2.sql"
version=2
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
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -1,7 +0,0 @@
.timeout 30000
BEGIN TRANSACTION;
UPDATE info SET value = 2 WHERE property = 'version';
COMMIT;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -1,229 +0,0 @@
#!/usr/bin/env bash
# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# allowlist and denylist domains
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
readonly utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck source="./advanced/Scripts/utils.sh"
source "${utilsfile}"
readonly 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
addmode=true
verbose=true
wildcard=false
domList=()
typeId=""
comment=""
colfile="/opt/pihole/COL_TABLE"
# shellcheck source="./advanced/Scripts/COL_TABLE"
source ${colfile}
helpFunc() {
echo "Usage: pihole ${abbrv} [options] <domain> <domain2 ...>
Example: 'pihole ${abbrv} site.com', or 'pihole ${abbrv} site1.com site2.com'
${typeId^} one or more ${kindId} domains
Options:
remove, delete, -d Remove domain(s)
-q, --quiet Make output less verbose
-h, --help Show this help dialog
-l, --list Display domains
--comment \"text\" Add a comment to the domain. If adding multiple domains the same comment will be used for all"
exit 0
}
CreateDomainList() {
# Format domain into regex filter if requested
local dom=${1}
if [[ "${wildcard}" == true ]]; then
dom="(\\.|^)${dom//\./\\.}$"
fi
domList=("${domList[@]}" "${dom}")
}
AddDomain() {
local json num data
# Authenticate with the API
LoginAPI
# Prepare request to POST /api/domains/{type}/{kind}
# Build JSON object of the following form
# {
# "domain": [ <domains> ],
# "comment": <comment>
# }
# 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
# Log out
LogoutAPI
}
RemoveDomain() {
local json num data status
# Authenticate with the API
LoginAPI
# Prepare request to POST /api/domains:batchDelete
# Build JSON object of the following form
# [{
# "item": <domain>,
# "type": "${typeId}",
# "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
# Log out
LogoutAPI
}
Displaylist() {
local data
# if either typeId or kindId is empty, we cannot display the list
if [[ -z "${typeId}" ]] || [[ -z "${kindId}" ]]; then
echo " ${CROSS} Unable to display list. Please specify a list type and kind."
exit 1
fi
# Authenticate with the API
LoginAPI
# 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
echo -e " ${INFO} No domains found in the ${kindId} ${typeId}list"
fi
# Log out
LogoutAPI
# Return early without adding/deleting domains
exit 0
}
GetComment() {
comment="$1"
if [[ "${comment}" =~ [^a-zA-Z0-9_\#:/\.,\ -] ]]; then
echo " ${CROSS} Found invalid characters in domain comment!"
exit 1
fi
}
while (( "$#" )); do
case "${1}" in
"allow" | "allowlist" ) kindId="exact"; typeId="allow"; abbrv="allow";;
"deny" | "denylist" ) kindId="exact"; typeId="deny"; abbrv="deny";;
"--allow-regex" | "allow-regex" ) kindId="regex"; typeId="allow"; abbrv="--allow-regex";;
"--allow-wild" | "allow-wild" ) kindId="regex"; typeId="allow"; wildcard=true; abbrv="--allow-wild";;
"--regex" | "regex" ) kindId="regex"; typeId="deny"; abbrv="--regex";;
"--wild" | "wildcard" ) kindId="regex"; typeId="deny"; wildcard=true; abbrv="--wild";;
"-d" | "remove" | "delete" ) addmode=false;;
"-q" | "--quiet" ) verbose=false;;
"-h" | "--help" ) helpFunc;;
"-l" | "--list" ) Displaylist;;
"--comment" ) GetComment "${2}"; shift;;
* ) CreateDomainList "${1}";;
esac
shift
done
shift
if [[ ${#domList[@]} == 0 ]]; then
helpFunc
fi
if ${addmode}; then
AddDomain
else
RemoveDomain
fi

View File

@@ -1,83 +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.
#
# 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
# shellcheck source="./advanced/Scripts/COL_TABLE"
source ${coltable}
fi
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
DBFILE=$(getFTLConfigValue "files.database")
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
# Stop FTL to prevent database access
if ! output=$(service pihole-FTL stop 2>&1); then
echo -e "${OVER} ${CROSS} Failed to stop FTL"
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 constraints
if ! output=$(pihole-FTL sqlite3 -ni "${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=$(pihole-FTL sqlite3 -ni "${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
# 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
# Start FTL again
if ! output=$(service pihole-FTL restart 2>&1); then
echo -e "${OVER} ${CROSS} Failed to restart FTL"
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

View File

@@ -1,245 +0,0 @@
#!/usr/bin/env bash
# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# Switch Pi-hole subsystems to a different GitHub branch.
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
SKIP_INSTALL="true"
# shellcheck source="./automated install/basic-install.sh"
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# webInterfaceGitUrl set in basic-install.sh
# webInterfaceDir set in basic-install.sh
# piholeGitURL set in basic-install.sh
# is_repo() sourced from basic-install.sh
# check_download_exists sourced from basic-install.sh
# fully_fetch_repo sourced from basic-install.sh
# get_available_branches sourced from basic-install.sh
# fetch_checkout_pull_branch sourced from basic-install.sh
# checkout_pull_branch sourced from basic-install.sh
warning1() {
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 -e " ${COL_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
case "${response}" in
[yY][eE][sS]|[yY])
echo ""
return 0
;;
*)
echo -e "\\n ${INFO} Branch change has been canceled"
return 1
;;
esac
}
checkout() {
local corebranches
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
set -f
# This is unlikely
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
echo -e " ${COL_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}"
exit 1;
fi
if ! is_repo "${webInterfaceDir}" ; then
echo -e " ${COL_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}"
exit 1;
fi
if [[ -z "${1}" ]]; then
echo -e " ${COL_RED}Invalid option${COL_NC}"
echo -e " Try 'pihole checkout --help' for more information."
exit 1
fi
if ! warning1 ; then
exit 1
fi
if [[ "${1}" == "dev" ]] ; then
# Shortcut to check out development branches
echo -e " ${INFO} Shortcut \"${COL_YELLOW}dev${COL_NC}\" detected - checking out development branches..."
echo ""
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; }
echo ""
echo -e " ${INFO} Web interface"
fetch_checkout_pull_branch "${webInterfaceDir}" "development" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; }
#echo -e " ${TICK} Pi-hole Core"
local path
path="development/${binary}"
echo "development" > /etc/pihole/ftlbranch
chmod 644 /etc/pihole/ftlbranch
elif [[ "${1}" == "master" ]] ; then
# Shortcut to check out master branches
echo -e " ${INFO} Shortcut \"${COL_YELLOW}master${COL_NC}\" detected - checking out master branches..."
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; }
echo -e " ${INFO} Web interface"
fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; }
#echo -e " ${TICK} Web Interface"
local path
path="master/${binary}"
echo "master" > /etc/pihole/ftlbranch
chmod 644 /etc/pihole/ftlbranch
elif [[ "${1}" == "core" ]] ; then
str="Fetching branches from ${piholeGitUrl}"
echo -ne " ${INFO} $str"
if ! fully_fetch_repo "${PI_HOLE_FILES_DIR}" ; then
echo -e "${OVER} ${CROSS} $str"
exit 1
fi
mapfile -t corebranches < <(get_available_branches "${PI_HOLE_FILES_DIR}")
if [[ "${corebranches[*]}" == *"master"* ]]; then
echo -e "${OVER} ${TICK} $str"
echo -e " ${INFO} ${#corebranches[@]} branches available for Pi-hole Core"
else
# Print STDERR output from get_available_branches
echo -e "${OVER} ${CROSS} $str\\n\\n${corebranches[*]}"
exit 1
fi
echo ""
# Have the user choose the branch they want
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} Available branches for Core are:"
for e in "${corebranches[@]}"; do echo " - $e"; done
exit 1
fi
checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}"
elif [[ "${1}" == "web" ]] ; then
str="Fetching branches from ${webInterfaceGitUrl}"
echo -ne " ${INFO} $str"
if ! fully_fetch_repo "${webInterfaceDir}" ; then
echo -e "${OVER} ${CROSS} $str"
exit 1
fi
mapfile -t webbranches < <(get_available_branches "${webInterfaceDir}")
if [[ "${webbranches[*]}" == *"master"* ]]; then
echo -e "${OVER} ${TICK} $str"
echo -e " ${INFO} ${#webbranches[@]} branches available for Web Admin"
else
# Print STDERR output from get_available_branches
echo -e "${OVER} ${CROSS} $str\\n\\n${webbranches[*]}"
exit 1
fi
echo ""
# Have the user choose the branch they want
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} Available branches for Web Admin are:"
for e in "${webbranches[@]}"; do echo " - $e"; done
exit 1
fi
checkout_pull_branch "${webInterfaceDir}" "${2}"
# Update local and remote versions via updatechecker
/opt/pihole/updatecheck.sh
elif [[ "${1}" == "ftl" ]] ; then
local path
local oldbranch
local existing=false
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
echo " ${TICK} Binary exists"
echo "${2}" > /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}"
restart_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
local status
status=$?
if [ $status -eq 1 ]; then
# Binary for requested branch is not available, may still be
# int he process of being built or CI build job failed
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
else
echo -e " ${CROSS} Requested option \"${1}\" is not available"
exit 1
fi
# Force updating everything
if [[ ! "${1}" == "web" && ! "${1}" == "ftl" ]]; then
echo -e " ${INFO} Running installer to upgrade your installation"
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
exit 0
else
echo -e " ${COL_RED} Error: Unable to complete update, please contact support${COL_NC}"
exit 1
fi
fi
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,118 +1,15 @@
#!/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.
# (c) 2015, 2016 by Jacob Salmela
# Network-wide ad blocking via your Raspberry Pi
# http://pi-hole.net
# Flushes /var/log/pihole.log
#
# Flushes 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 database location
DBFILE=$(getFTLConfigValue "files.database")
if [ -z "$DBFILE" ]; then
DBFILE="/etc/pihole/pihole-FTL.db"
fi
# 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
}
# Helper function to handle log flushing for a single file
flush_log() {
local logfile="$1"
if [[ "$*" != *"quiet"* ]]; then
echo -ne " ${INFO} Flushing ${logfile} ..."
fi
echo " " > "${logfile}"
chmod 640 "${logfile}"
if [ -f "${logfile}.1" ]; then
echo " " > "${logfile}.1"
chmod 640 "${logfile}.1"
fi
if [[ "$*" != *"quiet"* ]]; then
echo -e "${OVER} ${TICK} Flushed ${logfile} ..."
fi
}
if [[ "$*" == *"once"* ]]; then
# Nightly logrotation
if command -v /usr/sbin/logrotate >/dev/null; then
# Logrotate once
if [[ "$*" != *"quiet"* ]]; then
echo -ne " ${INFO} Running logrotate ..."
fi
/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
else
# Manual flushing
flush_log "${LOGFILE}"
flush_log "${FTLFILE}"
flush_log "${WEBFILE}"
if [[ "$*" != *"quiet"* ]]; then
echo -ne " ${INFO} Flushing database, DNS resolution temporarily unavailable ..."
fi
# Stop FTL to make sure it doesn't write to the database while we're deleting data
service pihole-FTL stop
# 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
# 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.
echo -n "::: Flushing /var/log/pihole.log ..."
truncate -s 0 /var/log/pihole.log
echo "... done!"

View File

@@ -1,154 +0,0 @@
#!/usr/bin/env sh
# Pi-hole: A black hole for Internet advertisements
# (c) 2023 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# Search Adlists
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
# Globals
PI_HOLE_INSTALL_DIR="/opt/pihole"
max_results="20"
partial="false"
domain=""
# Source color table
colfile="/opt/pihole/COL_TABLE"
# shellcheck source="./advanced/Scripts/COL_TABLE"
. "${colfile}"
# Source api functions
# shellcheck source="./advanced/Scripts/api.sh"
. "${PI_HOLE_INSTALL_DIR}/api.sh"
Help() {
echo "Usage: pihole -q [option] <domain>
Example: 'pihole -q --partial domain.com'
Query the adlists for a specified domain
Options:
--partial Search the adlists for partially matching domains
--all Return all query matches within the adlists
-h, --help Show this help dialog"
exit 0
}
GenerateOutput() {
local data gravity_data lists_data num_gravity num_lists search_type_str
local gravity_data_csv lists_data_csv line current_domain url type color
data="${1}"
# construct a new json for the list results where each object contains the domain and the related type
lists_data=$(printf %s "${data}" | jq '.search.domains | [.[] | {domain: .domain, type: .type}]')
# construct a new json for the gravity results where each object contains the adlist URL and the related domains
gravity_data=$(printf %s "${data}" | jq '.search.gravity | group_by(.address,.type) | map({ address: (.[0].address), type: (.[0].type), domains: [.[] | .domain] })')
# number of objects in each json
num_gravity=$(printf %s "${gravity_data}" | jq length)
num_lists=$(printf %s "${lists_data}" | jq length)
if [ "${partial}" = true ]; then
search_type_str="partially"
else
search_type_str="exactly"
fi
# Results from allow/deny list
printf "%s\n\n" "Found ${num_lists} domains ${search_type_str} matching '${COL_BLUE}${domain}${COL_NC}'."
if [ "${num_lists}" -gt 0 ]; then
# 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 "${lists_data}" | jq --raw-output '.[] | [.domain, .type] | join(",")')
# Generate output for each csv line, separating line in a domain and type substring at the ','
echo "${lists_data_csv}" | while read -r line; do
printf "%s\n\n" " - ${COL_GREEN}${line%,*}${COL_NC} (type: exact ${line#*,} domain)"
done
fi
# Results from gravity
printf "%s\n\n" "Found ${num_gravity} adlists ${search_type_str} matching '${COL_BLUE}${domain}${COL_NC}'."
if [ "${num_gravity}" -gt 0 ]; then
# Convert the data to a csv, each line is a "URL,domain,domain,...." string
# not using jq's @csv here as it quotes each value individually
gravity_data_csv=$(printf %s "${gravity_data}" | jq --raw-output '.[] | [.address, .type, .domains[]] | join(",")')
# Generate line-by-line output for each csv line
echo "${gravity_data_csv}" | while read -r line; do
# Get first part of the line, the URL
url=${line%%,*}
# cut off URL, leaving "type,domain,domain,...."
line=${line#*,}
type=${line%%,*}
# type == "block" -> red, type == "allow" -> green
if [ "${type}" = "block" ]; then
color="${COL_RED}"
else
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#*,}
# print each domain and remove it from the string until nothing is left
while [ ${#line} -gt 0 ]; do
current_domain=${line%%,*}
printf ' - %s\n' "${COL_GREEN}${current_domain}${COL_NC}"
# we need to remove the current_domain and the comma in two steps because
# the last domain won't have a trailing comma and the while loop wouldn't exit
line=${line#"${current_domain}"}
line=${line#,}
done
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
shift
done
Main "${domain}"

89
advanced/Scripts/setupLCD.sh Executable file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/env bash
# Pi-hole: A black hole for Internet advertisements
# (c) 2015 by Jacob Salmela
# Network-wide ad blocking via your Raspberry Pi
# http://pi-hole.net
# Automatically configures the Pi to use the 2.8 LCD screen to display stats on it (also works over ssh)
#
# 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.
############ FUNCTIONS ###########
# Run this script as root or under sudo
echo ":::"
if [[ $EUID -eq 0 ]];then
echo "::: You are root."
else
echo "::: sudo will be used."
# Check if it is actually installed
# If it isn't, exit because the install cannot complete
if [[ $(dpkg-query -s sudo) ]];then
export SUDO="sudo"
else
echo "::: Please install sudo or run this script as root."
exit 1
fi
fi
# 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
$SUDO systemctl set-default multi-user.target
$SUDO ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
else
$SUDO update-rc.d lightdm disable 2
$SUDO 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 | $SUDO bash
$SUDO apt-get -y install raspberrypi-bootloader
$SUDO apt-get -y install adafruit-pitft-helper
$SUDO adafruit-pitft-helper -t 28r
# Download the cmdline.txt file that prevents the screen from going blank after a period of time
$SUDO mv /boot/cmdline.txt /boot/cmdline.orig
$SUDO 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
$SUDO mv /etc/default/console-setup /etc/default/console-setup.orig
$SUDO 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
$SUDO setupcon
$SUDO 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'

View File

@@ -1,249 +0,0 @@
#!/usr/bin/env bash
# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# Check Pi-hole core and admin pages versions and determine what
# upgrade (if any) is required. Automatically updates and reinstalls
# application if update is detected.
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
# Variables
readonly ADMIN_INTERFACE_GIT_URL="https://github.com/pi-hole/web.git"
readonly PI_HOLE_GIT_URL="https://github.com/pi-hole/pi-hole.git"
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
SKIP_INSTALL=true
# when --check-only is passed to this script, it will not perform the actual update
CHECK_ONLY=false
# shellcheck source="./automated install/basic-install.sh"
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# shellcheck source=./advanced/Scripts/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
# make_repo() sourced from basic-install.sh
# update_repo() source from basic-install.sh
# getGitFiles() 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() {
local directory
local curBranch
directory="${1}"
curdir=$PWD
cd "${directory}" || exit 1
# Fetch latest changes in this repo
if ! git fetch --quiet origin ; then
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.
curBranch=$(git rev-parse --abbrev-ref HEAD)
if [[ "${curBranch}" == "master" ]]; then
# get the latest local tag
LOCAL=$(git describe --abbrev=0 --tags master)
# get the latest tag from remote
REMOTE=$(git describe --abbrev=0 --tags origin/master)
else
# @ alone is a shortcut for HEAD. Older versions of git
# need @{0}
LOCAL="$(git rev-parse "@{0}")"
# The suffix @{upstream} to a branchname
# (short form <branchname>@{u}) refers
# to the branch that the branch specified
# by branchname is set to build on top of#
# (configured with branch.<name>.remote and
# branch.<name>.merge). A missing branchname
# defaults to the current one.
REMOTE="$(git rev-parse "@{upstream}")"
fi
if [[ "${#LOCAL}" == 0 ]]; then
echo -e "\\n ${COL_RED}Error: Local revision could not be obtained, please contact Pi-hole Support"
echo -e " Additional debugging output:${COL_NC}"
git status
exit 1
fi
if [[ "${#REMOTE}" == 0 ]]; then
echo -e "\\n ${COL_RED}Error: Remote revision could not be obtained, please contact Pi-hole Support"
echo -e " Additional debugging output:${COL_NC}"
git status
exit 1
fi
# Change back to original directory
cd "${curdir}" || exit 1
if [[ "${LOCAL}" != "${REMOTE}" ]]; then
# Local branch is behind remote branch -> Update
return 0
else
# Local branch is up-to-date or in a situation
# where this updater cannot be used (like on a
# branch that exists only locally)
return 1
fi
}
main() {
local basicError="\\n ${COL_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
local core_update
local web_update
local FTL_update
core_update=false
web_update=false
FTL_update=false
# Install packages used by this installation script (necessary if users have removed e.g. git from their systems)
package_manager_detect
build_dependency_package
install_dependent_packages
# This is unlikely
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
echo -e "\\n ${COL_RED}Error: Core Pi-hole repo is missing from system!"
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
exit 1;
fi
echo -e " ${INFO} Checking for updates..."
if GitCheckUpdateAvail "${PI_HOLE_FILES_DIR}" ; then
core_update=true
echo -e " ${INFO} Pi-hole Core:\\t${COL_YELLOW}update available${COL_NC}"
else
core_update=false
echo -e " ${INFO} Pi-hole Core:\\t${COL_GREEN}up to date${COL_NC}"
fi
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
echo -e "\\n ${COL_RED}Error: Web Admin repo is missing from system!"
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
exit 1;
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_GREEN}up to date${COL_NC}"
fi
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
# Determine FTL branch
local ftlBranch
if [[ -f "/etc/pihole/ftlbranch" ]]; then
ftlBranch=$(</etc/pihole/ftlbranch)
else
ftlBranch="master"
fi
if [[ ! "${ftlBranch}" == "master" && ! "${ftlBranch}" == "development" ]]; then
# 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
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}"
fi
if [[ "${core_update}" == false && "${web_update}" == false && "${FTL_update}" == false ]]; then
echo ""
echo -e " ${TICK} Everything is up to date!"
exit 0
fi
if [[ "${CHECK_ONLY}" == true ]]; then
echo ""
exit 0
fi
if [[ "${core_update}" == true ]]; then
echo ""
echo -e " ${INFO} Pi-hole core files out of date, updating local repo."
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
echo -e " ${INFO} If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'"
fi
if [[ "${web_update}" == true ]]; then
echo ""
echo -e " ${INFO} Pi-hole Web Admin files out of date, updating local repo."
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'"
fi
if [[ "${FTL_update}" == true ]]; then
echo ""
echo -e " ${INFO} FTL out of date, it will be updated by the installer."
fi
if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --repair --unattended || \
echo -e "${basicError}" && exit 1
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 ""
exit 0
}
if [[ "$1" == "--check-only" ]]; then
CHECK_ONLY=true
fi
main

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env bash
# 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
# Updates the Pi-hole web interface
#
# 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.
WEB_INTERFACE_GIT_URL="https://github.com/pi-hole/AdminLTE.git"
WEB_INTERFACE_DIR="/var/www/html/admin"
main() {
prerequisites
if ! is_repo; then
make_repo
fi
update_repo
}
prerequisites() {
# must be root to update
if [[ $EUID -ne 0 ]]; then
sudo bash "$0" "$@"
exit $?
fi
# web interface must already exist. this is a (lazy)
# check to make sure pihole is actually installed.
if [ ! -d "$WEB_INTERFACE_DIR" ]; then
echo "$WEB_INTERFACE_DIR not found. Exiting."
exit 1
fi
if ! type "git" > /dev/null; then
apt-get -y install git
fi
}
is_repo() {
# if the web interface directory does not have a .git folder
# it means its using the master.zip archive from the install
# script.
if [ ! -d "$WEB_INTERFACE_DIR/.git" ]; then
return 1
fi
return 0
}
# removes the web interface installed from the master.zip archive and
# replaces it with the current master branch from github
make_repo() {
# remove the non-repod interface and clone the interface
rm -rf $WEB_INTERFACE_DIR
git clone "$WEB_INTERFACE_GIT_URL" "$WEB_INTERFACE_DIR"
}
# pulls the latest master branch from github
update_repo() {
# pull the latest commits
cd "$WEB_INTERFACE_DIR"
git pull
}
main

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# 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
# Checks if Pi-hole needs updating and then
#
# 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.
# Taken from http://stackoverflow.com/questions/3258243/check-if-pull-needed-in-git
# Move into the git directory
cd /etc/.pihole/
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse @{u})
BASE=$(git merge-base @ @{u})
if [[ $LOCAL = $REMOTE ]]; then
echo "Up-to-date"
elif [[ $LOCAL = $BASE ]]; then
echo "Updating Pi-hole..."
git pull
/opt/pihole/updatePiholeSecondary.sh
elif [[ $REMOTE = $BASE ]]; then
: # Need to push, so do nothing
else
: # Diverged, so do nothing
fi

View File

@@ -0,0 +1,103 @@
#!/usr/bin/env bash
# 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
# Checks if Pi-hole needs updating and then
#
# 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.
# Must be root to use this tool
if [[ ! $EUID -eq 0 ]];then
#echo "::: You are root."
#else
#echo "::: Sudo will be used for this tool."
# Check if it is actually installed
# If it isn't, exit because the pihole cannot be invoked without privileges.
if [[ $(dpkg-query -s sudo) ]];then
export SUDO="sudo"
else
echo "::: Please install sudo or run this as root."
exit 1
fi
fi
function updateDependencies(){
#Add any new dependencies to the below array`
newDependencies=()
echo "::: Installing any new dependencies..."
for i in "${newDependencies[@]}"; do
echo "checking for $i"
if [ "$(dpkg-query -W -f='${Status}' "$i" 2>/dev/null | grep -c "ok installed")" -eq 0 ]; then
echo -n " Not found! Installing...."
$SUDO apt-get -y -qq install "$i" > /dev/null & spinner $!
echo " done!"
else
echo " already installed!"
fi
done
}
}
stopServices() {
# Stop dnsmasq and lighttpd
echo ":::"
echo -n "::: Stopping services..."
$SUDO service lighttpd stop
echo " done."
}
installScripts() {
# Install the scripts from /etc/.pihole to their various locations
echo ":::"
echo -n "::: Updating scripts in /opt/pihole..."
$SUDO cp /etc/.pihole/gravity.sh /opt/pihole/gravity.sh
$SUDO cp /etc/.pihole/advanced/Scripts/chronometer.sh /opt/pihole/chronometer.sh
$SUDO cp /etc/.pihole/advanced/Scripts/whitelist.sh /opt/pihole/whitelist.sh
$SUDO cp /etc/.pihole/advanced/Scripts/blacklist.sh /opt/pihole/blacklist.sh
$SUDO cp /etc/.pihole/advanced/Scripts/piholeDebug.sh /opt/pihole/piholeDebug.sh
$SUDO cp /etc/.pihole/advanced/Scripts/piholeLogFlush.sh /opt/pihole/piholeLogFlush.sh
$SUDO cp /etc/.pihole/advanced/Scripts/updateDashboard.sh /opt/pihole/updateDashboard.sh
$SUDO cp /etc/.pihole/advanced/Scripts/updatePihole.sh /opt/pihole/updatePihole.sh
$SUDO cp /etc/.pihole/advanced/Scripts/updatePiholeSecondary.sh /opt/pihole/updatePiholeSecondary.sh
$SUDO cp /etc/.pihole/automated\ install/uninstall.sh /opt/pihole/uninstall.sh
$SUDO cp /etc/.pihole/advanced/Scripts/setupLCD.sh /opt/pihole/setupLCD.sh
$SUDO chmod 755 /opt/pihole/{gravity,chronometer,whitelist,blacklist,piholeLogFlush,updateDashboard,updatePihole,updatePiholeSecondary,uninstall,setupLCD, piholeDebug}.sh
$SUDO cp /etc/.pihole/pihole /usr/local/bin/pihole
$SUDO chmod 755 /usr/local/bin/pihole
$SUDO cp /etc/.pihole/advanced/bash-completion/pihole /etc/bash_completion.d/pihole
. /etc/bash_completion.d/pihole
#Tidy up /usr/local/bin directory if updating an old installation (can probably be removed at some point)
oldFiles=( gravity chronometer whitelist blacklist piholeLogFlush updateDashboard updatePihole updatePiholeSecondary uninstall setupLCD piholeDebug)
for i in "${oldFiles[@]}"; do
if [ -f "/usr/local/bin/$i.sh" ]; then
$SUDO rm /usr/local/bin/"$i".sh
fi
done
echo " done."
}
########################
# SCRIPT STARTS HERE! #
#######################
#uncomment the below if adding new dependencies (don't forget to update the install script!)
#updateDependencies
stopServices
installScripts
#TODO:
# - Distribute files`
# - Run pihole -g
# - add root check, maybe? Do we need to? Probably a good idea.
# - update install script to populate a config file with:
# -IPv4
# -IPv6
# -UpstreamDNS servers

View File

@@ -1,136 +0,0 @@
#!/usr/bin/env bash
# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# Checks for local or remote versions and branches
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
function get_local_branch() {
# Return active branch
cd "${1}" 2>/dev/null || return 1
git rev-parse --abbrev-ref HEAD || return 1
}
function get_local_version() {
# Return active version
cd "${1}" 2>/dev/null || return 1
git describe --tags --always 2>/dev/null || return 1
}
function get_local_hash() {
cd "${1}" 2>/dev/null || return 1
git rev-parse --short=8 HEAD || return 1
}
function get_remote_version() {
# 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 || return 1
else
echo "null"
fi
}
function get_remote_hash() {
git ls-remote "https://github.com/pi-hole/${1}" --tags "${2}" | awk '{print substr($0, 1,8);}' || return 1
}
# 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"
# Create new versions file if it does not exist
VERSION_FILE="/etc/pihole/versions"
touch "${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
GITHUB_DOCKER_VERSION="$(get_remote_version docker-pi-hole "${docker_branch}")"
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_DOCKER_VERSION" "${GITHUB_DOCKER_VERSION}"
fi

View File

@@ -1,94 +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}"
# touch file to prevent grep error if file does not exist yet
touch "${file}"
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(){
pihole-FTL --config -q "${1}"
}
#######################
# 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(){
pihole-FTL --config "${1}" "${2}" >/dev/null
if [ $? -eq 5 ]; then
printf " %s %s set by environment variable. Please unset it to use this function\n" "${CROSS}" "${1}"
exit 5
fi
}

View File

@@ -1,54 +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.
#
# Show version numbers
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
# Source the versions file populated by updatechecker.sh
cachedVersions="/etc/pihole/versions"
if [ -f ${cachedVersions} ]; then
# shellcheck source=/dev/null
. "$cachedVersions"
else
echo "Could not find /etc/pihole/versions. Running update now."
pihole updatechecker
# shellcheck source=/dev/null
. "$cachedVersions"
fi
main() {
local details
details=false
# Automatically show detailed information if
# 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
if [ "${details}" = true ]; then
echo "Core"
echo " Version is ${CORE_VERSION:=N/A} (Latest: ${GITHUB_CORE_VERSION:=N/A})"
echo " Branch is ${CORE_BRANCH:=N/A}"
echo " Hash is ${CORE_HASH:=N/A} (Latest: ${GITHUB_CORE_HASH:=N/A})"
echo "Web"
echo " Version is ${WEB_VERSION:=N/A} (Latest: ${GITHUB_WEB_VERSION:=N/A})"
echo " Branch is ${WEB_BRANCH:=N/A}"
echo " Hash is ${WEB_HASH:=N/A} (Latest: ${GITHUB_WEB_HASH:=N/A})"
echo "FTL"
echo " Version is ${FTL_VERSION:=N/A} (Latest: ${GITHUB_FTL_VERSION:=N/A})"
echo " Branch is ${FTL_BRANCH:=N/A}"
echo " Hash is ${FTL_HASH:=N/A} (Latest: ${GITHUB_FTL_HASH:=N/A})"
else
echo "Core version is ${CORE_VERSION:=N/A} (Latest: ${GITHUB_CORE_VERSION:=N/A})"
echo "Web version is ${WEB_VERSION:=N/A} (Latest: ${GITHUB_WEB_VERSION:=N/A})"
echo "FTL version is ${FTL_VERSION:=N/A} (Latest: ${GITHUB_FTL_VERSION:=N/A})"
fi
}
main

256
advanced/Scripts/whitelist.sh Executable file
View File

@@ -0,0 +1,256 @@
#!/usr/bin/env bash
# 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
# Whitelists domains
#
# 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.
#rootcheck
if [[ $EUID -eq 0 ]];then
echo "::: You are root."
else
echo "::: sudo will be used."
# Check if it is actually installed
# If it isn't, exit because the install cannot complete
if [[ $(dpkg-query -s sudo) ]];then
export SUDO="sudo"
else
echo "::: Please install sudo or run this script as root."
exit 1
fi
fi
if [[ $# = 0 ]]; then
helpFunc
fi
#globals
basename=pihole
piholeDir=/etc/$basename
adList=$piholeDir/gravity.list
whitelist=$piholeDir/whitelist.txt
reload=true
addmode=true
force=false
verbose=true
domList=()
domToRemoveList=()
piholeIPfile=/etc/pihole/piholeIP
piholeIPv6file=/etc/pihole/.useIPv6
if [[ -f $piholeIPfile ]];then
# If the file exists, it means it was exported from the installation script and we should use that value instead of detecting it in this script
piholeIP=$(cat $piholeIPfile)
#rm $piholeIPfile
else
# Otherwise, the IP address can be taken directly from the machine, which will happen when the script is run by the user and not the installation script
IPv4dev=$(ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++)if($i~/dev/)print $(i+1)}')
piholeIPCIDR=$(ip -o -f inet addr show dev "$IPv4dev" | awk '{print $4}' | awk 'END {print}')
piholeIP=${piholeIPCIDR%/*}
fi
modifyHost=false
# After setting defaults, check if there's local overrides
if [[ -r $piholeDir/pihole.conf ]];then
echo "::: Local calibration requested..."
. $piholeDir/pihole.conf
fi
if [[ -f $piholeIPv6file ]];then
# If the file exists, then the user previously chose to use IPv6 in the automated installer
piholeIPv6=$(ip -6 route get 2001:4860:4860::8888 | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "src") print $(i+1) }')
fi
function helpFunc()
{
echo "::: Immediately whitelists one or more domains in the hosts file"
echo ":::"
echo "::: Usage: pihole -w domain1 [domain2 ...]"
echo ":::"
echo "::: Options:"
echo "::: -d, --delmode Remove domains from the whitelist"
echo "::: -nr, --noreload Update Whitelist without refreshing dnsmasq"
echo "::: -f, --force Force updating of the hosts files, even if there are no changes"
echo "::: -q, --quiet output is less verbose"
echo "::: -h, --help Show this help dialog"
echo "::: -l, --list Display your whitelisted domains"
exit 1
}
if [[ $# = 0 ]]; then
helpFunc
fi
function HandleOther(){
#check validity of domain
validDomain=$(echo "$1" | perl -ne'print if /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/')
if [ -z "$validDomain" ]; then
echo "::: $1 is not a valid argument or domain name"
else
domList=("${domList[@]}" $validDomain)
fi
}
function PopWhitelistFile(){
#check whitelist file exists, and if not, create it
if [[ ! -f $whitelist ]];then
touch $whitelist
fi
for dom in "${domList[@]}"
do
if $addmode; then
AddDomain "$dom"
else
RemoveDomain "$dom"
fi
done
}
function AddDomain(){
#| sed 's/\./\\./g'
bool=false
grep -Ex -q "$1" $whitelist || bool=true
if $bool; then
#domain not found in the whitelist file, add it!
if $verbose; then
echo -n "::: Adding $1 to $whitelist..."
fi
echo "$1" >> $whitelist
modifyHost=true
if $verbose; then
echo " done!"
fi
else
if $verbose; then
echo "::: $1 already exists in $whitelist, no need to add!"
fi
fi
}
function RemoveDomain(){
bool=false
grep -Ex -q "$1" $whitelist || bool=true
if $bool; then
#Domain is not in the whitelist file, no need to Remove
if $verbose; then
echo "::: $1 is NOT whitelisted! No need to remove"
fi
else
#Domain is in the whitelist file, add to a temporary array and remove from whitelist file
#if $verbose; then
#echo "::: Un-whitelisting $dom..."
#fi
domToRemoveList=("${domToRemoveList[@]}" $1)
modifyHost=true
fi
}
function ModifyHostFile(){
if $addmode; then
#remove domains in from hosts file
if [[ -r $whitelist ]];then
# Remove whitelist entries
numberOf=$(cat $whitelist | sed '/^\s*$/d' | wc -l)
plural=; [[ "$numberOf" != "1" ]] && plural=s
echo ":::"
echo -n "::: Modifying HOSTS file to whitelist $numberOf domain${plural}..."
awk -F':' '{print $1}' $whitelist | while read -r line; do echo "$piholeIP $line"; done > /etc/pihole/whitelist.tmp
awk -F':' '{print $1}' $whitelist | while read -r line; do echo "$piholeIPv6 $line"; done >> /etc/pihole/whitelist.tmp
echo "l" >> /etc/pihole/whitelist.tmp
grep -F -x -v -f $piholeDir/whitelist.tmp $adList > $piholeDir/gravity.tmp
rm $adList
mv $piholeDir/gravity.tmp $adList
rm $piholeDir/whitelist.tmp
echo " done!"
fi
else
#we need to add the removed domains to the hosts file
echo ":::"
echo "::: Modifying HOSTS file to un-whitelist domains..."
for rdom in "${domToRemoveList[@]}"
do
if [[ -n $piholeIPv6 ]];then
echo -n "::: Un-whitelisting $rdom on IPv4 and IPv6..."
echo "$rdom" | awk -v ipv4addr="$piholeIP" -v ipv6addr="$piholeIPv6" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> $adList
echo " done!"
else
echo -n "::: Un-whitelisting $rdom on IPv4"
echo "$rdom" | awk -v ipv4addr="$piholeIP" '{sub(/\r$/,""); print ipv4addr" "$0}' >>$adList
echo " done!"
fi
echo -n "::: Removing $rdom from $whitelist..."
echo "$rdom" | sed 's/\./\\./g' | xargs -I {} perl -i -ne'print unless /'{}'(?!.)/;' $whitelist
echo " done!"
done
fi
}
function Reload() {
# Reload hosts file
echo ":::"
echo -n "::: Refresh lists in dnsmasq..."
dnsmasqPid=$(pidof dnsmasq)
if [[ $dnsmasqPid ]]; then
# service already running - reload config
$SUDO killall -s HUP dnsmasq
else
# service not running, start it up
$SUDO service dnsmasq start
fi
echo " done!"
}
function DisplayWlist() {
verbose=false
echo -e " Displaying Gravity Resistant Domains \n"
count=1
while IFS= read -r RD
do
echo "${count}: $RD"
count=$((count+1))
done < "$whitelist"
}
###################################################
for var in "$@"
do
case "$var" in
"-nr"| "--noreload" ) reload=false;;
"-d" | "--delmode" ) addmode=false;;
"-f" | "--force" ) force=true;;
"-q" | "--quiet" ) verbose=false;;
"-h" | "--help" ) helpFunc;;
"-l" | "--list" ) DisplayWlist;;
* ) HandleOther "$var";;
esac
done
PopWhitelistFile
if $modifyHost || $force; then
ModifyHostFile
else
if $verbose; then
echo ":::"
echo "::: No changes need to be made"
fi
exit 1
fi
if $reload; then
Reload
fi

View File

@@ -1,205 +0,0 @@
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
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
);
INSERT INTO "group" (id,enabled,name,description) VALUES (0,1,'Default','The default group');
CREATE TABLE domainlist
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
type INTEGER NOT NULL DEFAULT 0,
domain TEXT 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,
UNIQUE(domain, type)
);
CREATE TABLE adlist
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
address TEXT 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,
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
(
adlist_id INTEGER NOT NULL REFERENCES adlist (id) ON DELETE CASCADE,
group_id INTEGER NOT NULL REFERENCES "group" (id) ON DELETE CASCADE,
PRIMARY KEY (adlist_id, group_id)
);
CREATE TABLE gravity
(
domain TEXT NOT NULL,
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
(
property TEXT PRIMARY KEY,
value TEXT NOT NULL
);
INSERT INTO "info" VALUES('version','19');
/* 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
(
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_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;
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;
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;
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;
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);
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;
CREATE VIEW vw_adlist AS SELECT DISTINCT address, id, type
FROM adlist
WHERE enabled = 1
ORDER BY id;
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_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;

View File

@@ -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;

View File

@@ -1,32 +0,0 @@
/var/log/pihole/pihole.log {
# su #
daily
copytruncate
rotate 5
compress
delaycompress
notifempty
nomail
}
/var/log/pihole/FTL.log {
# su #
weekly
copytruncate
rotate 3
compress
delaycompress
notifempty
nomail
}
/var/log/pihole/webserver.log {
# su #
weekly
copytruncate
rotate 3
compress
delaycompress
notifempty
nomail
}

View File

@@ -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}"

View File

@@ -1,34 +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)"
# 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)
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 /var/log/pihole/FTL.log ] || install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/FTL.log
[ -f /var/log/pihole/pihole.log ] || install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/pihole.log
[ -f /var/log/pihole/webserver.log ] || install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/webserver.log
[ -f /etc/pihole/dhcp.leases ] || install -m 644 -o pihole -g pihole /dev/null /etc/pihole/dhcp.leases

View File

@@ -1,125 +0,0 @@
#!/usr/bin/env sh
### BEGIN INIT INFO
# Provides: pihole-FTL
# Required-Start: $remote_fs $syslog $network
# Required-Stop: $remote_fs $syslog $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: pihole-FTL daemon
# Description: Enable service provided by pihole-FTL daemon
### END INIT INFO
# Source utils.sh for getFTLConfigValue(), getFTLPID()
PI_HOLE_SCRIPT_DIR="/opt/pihole"
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck source="./advanced/Scripts/utils.sh"
. "${utilsfile}"
is_running() {
if [ -d "/proc/${FTL_PID}" ]; then
return 0
fi
return 1
}
cleanup() {
# Run post-stop script, which does cleanup among runtime files
sh "${PI_HOLE_SCRIPT_DIR}/pihole-FTL-poststop.sh"
}
# Start the service
start() {
if is_running; then
echo "pihole-FTL is already running"
else
# Run pre-start script, which pre-creates all expected files with correct permissions
sh "${PI_HOLE_SCRIPT_DIR}/pihole-FTL-prestart.sh"
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
su -s /bin/sh -c "/usr/bin/pihole-FTL" pihole
else
echo "Warning: Starting pihole-FTL as root because setting capabilities is not supported on this system"
/usr/bin/pihole-FTL
fi
rc=$?
# Cleanup if startup failed
if [ "${rc}" != 0 ]; then
cleanup
exit $rc
fi
echo
fi
}
# Stop the service
stop() {
if is_running; then
kill "${FTL_PID}"
# Give FTL 60 seconds to gracefully stop
i=1
while [ "${i}" -le 60 ]; do
if ! is_running; then
break
fi
printf "."
sleep 1
i=$((i + 1))
done
echo
if is_running; then
echo "Not stopped; may still be shutting down or shutdown may have failed, killing now"
kill -9 "${FTL_PID}"
else
echo "Stopped"
fi
else
echo "Not running"
fi
cleanup
echo
}
# Indicate the service status
status() {
if is_running; then
echo "[ ok ] pihole-FTL is running"
exit 0
else
echo "[ ] pihole-FTL is not running"
exit 1
fi
}
### 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
stop)
stop
;;
status)
status
;;
start|restart|reload|condrestart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart|reload|status}"
exit 1
esac
exit 0

View File

@@ -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
PermissionsStartOnly=true
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN CAP_SYS_NICE CAP_IPC_LOCK CAP_CHOWN CAP_SYS_TIME
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=60s
# 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

View File

@@ -1,33 +0,0 @@
# 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.
#
# Updates ad sources every week
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
#
#
#
# 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
# is updated or re-installed. Please make any changes to the appropriate crontab
# or other cron file snippets.
# Pi-hole: Update the ad sources once a week on Sunday at a random time in the
# early morning. Download any updates from the adlists
# Squash output to log, then splat the log to stdout on error to allow for
# 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
# Pi-hole: Flush the log daily at 00:00
# The flush script will use logrotate if available
# parameter "once": logrotate only once (default is twice)
# parameter "quiet": don't print messages
00 00 * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole flush once quiet
@reboot root /usr/sbin/logrotate --state /var/lib/logrotate/pihole /etc/pihole/logrotate
# Pi-hole: Grab remote and local version every 24 hours
59 17 * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker
@reboot root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker reboot

View File

@@ -1,51 +1,12 @@
_pihole() {
local cur prev opts opts_checkout opts_debug opts_logging opts_query opts_update opts_version
_pihole()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
prev2="${COMP_WORDS[COMP_CWORD-2]}"
opts="whitelist blacklist debug flush updateDashboard updateGravity setupLCD chronometer uninstall help"
case "${prev}" in
"pihole")
opts="allow allow-regex allow-wild deny checkout debug disable enable flush help logging query repair regex reloaddns reloadlists status tail uninstall updateGravity updatePihole version wildcard arpflush api"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
;;
"allow"|"deny"|"wildcard"|"regex"|"allow-regex"|"allow-wild")
opts_lists="\not \--delmode \--quiet \--list \--help"
COMPREPLY=( $(compgen -W "${opts_lists}" -- ${cur}) )
;;
"checkout")
opts_checkout="core ftl web master dev"
COMPREPLY=( $(compgen -W "${opts_checkout}" -- ${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="--partial --all"
COMPREPLY=( $(compgen -W "${opts_query}" -- ${cur}) )
;;
"updatePihole"|"-up")
opts_update="--check-only"
COMPREPLY=( $(compgen -W "${opts_update}" -- ${cur}) )
;;
"core"|"admin"|"ftl")
if [[ "$prev2" == "checkout" ]]; then
opts_checkout="master dev"
COMPREPLY=( $(compgen -W "${opts_checkout}" -- ${cur}) )
else
return 1
fi
;;
*)
return 1
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
}
complete -F _pihole pihole
complete -F _pihole pihole

1
advanced/cmdline.txt Normal file
View 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
View 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'

View 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

12
advanced/dphys-swapfile Normal file
View File

@@ -0,0 +1,12 @@
# 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
# Swap file config
#
# 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.
CONF_SWAPSIZE=500

4
advanced/index.html Normal file
View File

@@ -0,0 +1,4 @@
<html>
<body>
</body>
</html>

1
advanced/index.js Normal file
View File

@@ -0,0 +1 @@
var x = "Pi-hole: A black hole for Internet advertisements."

61
advanced/lighttpd.conf Normal file
View File

@@ -0,0 +1,61 @@
# 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 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_accesslog",
"mod_expire",
"mod_compress",
"mod_redirect",
"mod_setenv",
"mod_rewrite"
)
server.document-root = "/var/www/html"
server.error-handler-404 = "pihole/index.html"
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" )
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"
# 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"
)
}
# If the URL does not start with /admin, then it is a query for an ad domain
$HTTP["url"] =~ "^(?!/admin)/.*" {
# Create a response header for debugging using curl -I
setenv.add-response-header = ( "X-Pi-hole" => "A black hole for Internet advertisements." )
# rewrite only js requests
url.rewrite = ("(.*).js" => "pihole/index.js")
}

30
advanced/pihole.cron Normal file
View File

@@ -0,0 +1,30 @@
# 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
# Updates ad sources every week
#
# 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.
# Pi-hole: Check if Pi-hole needs to be updated. Check once a week on Monday at 23:58
# New releases often come out on Sunday, so checking the next day should be effective.
#23 58 * * 1 root /usr/local/bin/updatePihole
# Pi-hole: Update the ad sources once a week on Sunday at 01:59
# Download any updates from the adlists
59 1 * * 7 root /usr/local/bin/pihole updateGravity
# Pi-hole: Update the Web interface shortly after gravity runs
# This should also update the version number if it is changed in the dashboard repo
30 2 * * 7 root /usr/local/bin/pihole updateDashboard
# Pi-hole: Parse the log file before it is flushed and save the stats to a database
# This will be used for a historical view of your Pi-hole's performance
#50 23 * * * root /usr/local/bin/dailyLog.sh # note: this is outdated
# Pi-hole: Flush the log daily at 11:58 so it doesn't get out of control
# Stats will be viewable in the Web interface thanks to the cron job above
58 23 * * * root /usr/local/bin/pihole flush

File diff suppressed because it is too large Load Diff

View File

@@ -1,162 +1,146 @@
#!/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.
#
# (c) 2015, 2016 by Jacob Salmela
# Network-wide ad blocking via your Raspberry Pi
# http://pi-hole.net
# Completely uninstalls Pi-hole
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
# shellcheck source="./advanced/Scripts/COL_TABLE"
source "/opt/pihole/COL_TABLE"
# shellcheck source="./advanced/Scripts/utils.sh"
source "/opt/pihole/utils.sh"
ADMIN_INTERFACE_DIR=$(getFTLConfigValue "webserver.paths.webroot")$(getFTLConfigValue "webserver.paths.webhome")
readonly ADMIN_INTERFACE_DIR
while true; do
read -rp " ${QST} Are you sure you would like to remove ${COL_BOLD}Pi-hole${COL_NC}? [y/N] " answer
case ${answer} in
[Yy]* ) break;;
* ) echo -e "${OVER} ${COL_GREEN}Uninstall has been canceled${COL_NC}"; exit 0;;
esac
done
# 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.
# Must be root to uninstall
str="Root user check"
if [[ ${EUID} -eq 0 ]]; then
echo -e " ${TICK} ${str}"
if [[ $EUID -eq 0 ]];then
echo "::: You are root."
else
# Check if sudo is actually installed
# If it isn't, exit because the uninstall can not complete
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 privileges to uninstall"
exit 1
fi
echo "::: Sudo will be used for the uninstall."
# Check if it is actually installed
# If it isn't, exit because the unnstall cannot complete
if [[ $(dpkg-query -s sudo) ]];then
export SUDO="sudo"
else
echo "::: Please install sudo or run this as root."
exit 1
fi
fi
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
SKIP_INSTALL="true"
# shellcheck source="./automated install/basic-install.sh"
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# package_manager_detect() sourced from basic-install.sh
package_manager_detect
removeMetaPackage() {
# Purge Pi-hole meta package
echo ""
echo -ne " ${INFO} Removing Pi-hole meta package...";
eval "${SUDO}" "${PKG_REMOVE}" "pihole-meta" &> /dev/null;
echo -e "${OVER} ${INFO} Removed Pi-hole meta package";
spinner()
{
local pid=$1
local delay=0.50
local spinstr='/-\|'
while [ "$(ps a | awk '{print $1}' | grep "$pid")" ]; do
local temp=${spinstr#?}
printf " [%c] " "$spinstr"
local spinstr=$temp${spinstr%"$temp"}
sleep $delay
printf "\b\b\b\b\b\b"
done
printf " \b\b\b\b"
}
removePiholeFiles() {
# Remove the web interface of Pi-hole
echo -ne " ${INFO} Removing Web Interface..."
${SUDO} rm -rf "${ADMIN_INTERFACE_DIR}" &> /dev/null
echo -e "${OVER} ${TICK} Removed Web Interface"
function removeAndPurge {
# Purge dependencies
echo ":::"
# Nate 3/28/2016 - Removed `php5-cgi` and `php5` as they are removed with php5-common
dependencies=( dnsutils bc dnsmasq lighttpd php5-common git curl unzip wget )
for i in "${dependencies[@]}"; do
if [ "$(dpkg-query -W --showformat='${Status}\n' "$i" 2> /dev/null | grep -c "ok installed")" -eq 1 ]; then
while true; do
read -rp "::: Do you wish to remove $i from your system? [y/n]: " yn
case $yn in
[Yy]* ) printf ":::\tRemoving %s..." "$i"; $SUDO apt-get -y remove --purge "$i" &> /dev/null & spinner $!; printf "done!\n"; break;;
[Nn]* ) printf ":::\tSkipping %s" "$i\n"; break;;
* ) printf "::: You must answer yes or no!\n";;
esac
done
else
printf ":::\tPackage %s not installed... Not removing.\n" "$i"
fi
done
# Attempt to preserve backwards compatibility with older versions
# to guarantee no additional changes were made to /etc/crontab after
# the installation of pihole, /etc/crontab.pihole should be permanently
# preserved.
if [[ -f /etc/crontab.orig ]]; then
${SUDO} mv /etc/crontab /etc/crontab.pihole
${SUDO} mv /etc/crontab.orig /etc/crontab
${SUDO} service cron restart
echo -e " ${TICK} Restored the default system cron"
fi
# Remove dependency config files
echo "::: Removing dnsmasq config files..."
$SUDO rm /etc/dnsmasq.conf /etc/dnsmasq.conf.orig /etc/dnsmasq.d/01-pihole.conf &> /dev/null
# Attempt to preserve backwards compatibility with older versions
if [[ -f /etc/cron.d/pihole ]];then
${SUDO} rm -f /etc/cron.d/pihole &> /dev/null
echo -e " ${TICK} Removed /etc/cron.d/pihole"
fi
# Take care of any additional package cleaning
printf "::: Auto removing remaining dependencies..."
$SUDO apt-get -y autoremove &> /dev/null & spinner $!; printf "done!\n";
printf "::: Auto cleaning remaining dependencies..."
$SUDO apt-get -y autoclean &> /dev/null & spinner $!; printf "done!\n";
${SUDO} rm -rf /var/log/*pihole* &> /dev/null
${SUDO} rm -rf /var/log/pihole/*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"
# Call removeNoPurge to remove PiHole specific files
removeNoPurge
}
# Restore Resolved
if [[ -e /etc/systemd/resolved.conf.orig ]] || [[ -e /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf ]]; then
${SUDO} cp -p /etc/systemd/resolved.conf.orig /etc/systemd/resolved.conf &> /dev/null || true
${SUDO} rm -f /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf
systemctl reload-or-restart systemd-resolved
fi
function removeNoPurge {
echo ":::"
# Only web directories/files that are created by pihole should be removed.
echo "::: Removing the Pi-hole Web server files..."
$SUDO rm -rf /var/www/html/admin &> /dev/null
$SUDO rm -rf /var/www/html/pihole &> /dev/null
$SUDO rm /var/www/html/index.lighttpd.orig &> /dev/null
# 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/systemd/system/pihole-FTL.service
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..."
${SUDO} rm -R /etc/systemd/system/pihole-FTL.service.d
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
${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 web directory is empty after removing these files, then the parent html folder 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
# 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"
fi
# Attempt to preserve backwards compatibility with older versions
# to guarantee no additional changes were made to /etc/crontab after
# the installation of pihole, /etc/crontab.pihole should be permanently
# preserved.
if [[ -f /etc/crontab.orig ]]; then
echo "::: Initial Pi-hole cron detected. Restoring the default system cron..."
$SUDO mv /etc/crontab /etc/crontab.pihole
$SUDO mv /etc/crontab.orig /etc/crontab
$SUDO service cron restart
fi
# If the pihole user exists, then remove
if id "pihole" &> /dev/null; then
if ${SUDO} userdel -r pihole 2> /dev/null; then
echo -e " ${TICK} Removed 'pihole' user"
else
echo -e " ${CROSS} Unable to remove 'pihole' user"
fi
fi
# If the pihole group exists, then remove
if getent group "pihole" &> /dev/null; then
if ${SUDO} groupdel pihole 2> /dev/null; then
echo -e " ${TICK} Removed 'pihole' group"
else
echo -e " ${CROSS} Unable to remove 'pihole' group"
fi
fi
# Attempt to preserve backwards compatibility with older versions
if [[ -f /etc/cron.d/pihole ]];then
echo "::: Removing cron.d/pihole..."
$SUDO rm /etc/cron.d/pihole &> /dev/null
fi
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
Reinstall at any time: ${COL_BOLD}curl -sSL https://install.pi-hole.net | bash${COL_NC}
echo "::: Removing config files and scripts..."
if [ ! "$(dpkg-query -W --showformat='${Status}\n' lighttpd 2> /dev/null | grep -c "ok installed")" -eq 1 ]; then
$SUDO rm -rf /etc/lighttpd/ &> /dev/null
else
if [ -f /etc/lighttpd/lighttpd.conf.orig ]; then
$SUDO mv /etc/lighttpd/lighttpd.conf.orig /etc/lighttpd/lighttpd.conf
fi
fi
${COL_RED}Please reset the DNS on your router/clients to restore internet connectivity${COL_NC}
${INFO} Pi-hole's meta package has been removed, use the 'autoremove' function from your package manager to remove unused dependencies${COL_NC}
${COL_GREEN}Uninstallation Complete! ${COL_NC}"
$SUDO rm /etc/dnsmasq.d/adList.conf &> /dev/null
$SUDO rm /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 /usr/local/bin/pihole &> /dev/null
$SUDO rm /etc/bash_completion.d/pihole
echo ":::"
printf "::: Finished removing PiHole from your system. Sorry to see you go!\n"
printf "::: Reach out to us at https://github.com/pi-hole/pi-hole/issues if you need help\n"
printf "::: Reinstall by simpling running\n:::\n:::\tcurl -L https://install.pi-hole.net | bash\n:::\n::: at any time!\n:::\n"
printf "::: PLEASE RESET YOUR DNS ON YOUR ROUTER/CLIENTS TO RESTORE INTERNET CONNECTIVITY!\n"
}
######### SCRIPT ###########
removeMetaPackage
removePiholeFiles
echo "::: Preparing to remove packages, be sure that each may be safely removed depending on your operating system."
echo "::: (SAFE TO REMOVE ALL ON RASPBIAN)"
while true; do
read -rp "::: Do you wish to purge PiHole's dependencies from your OS? (You will be prompted for each package) [y/n]: " yn
case $yn in
[Yy]* ) removeAndPurge; break;;
[Nn]* ) removeNoPurge; break;;
esac
done

View 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")
}

View 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

1452
gravity.sh

File diff suppressed because it is too large Load Diff

View File

@@ -1,338 +0,0 @@
.TH "Pi-hole" "8" "Pi-hole" "Pi-hole" "April 2020"
.SH "NAME"
Pi-hole : A black-hole for internet advertisements
.br
.SH "SYNOPSIS"
\fBpihole\fR (\fB-allow\fR|\fB-deny\fR) [options] domain(s)
.br
\fBpihole\fR (\fB--allow-regex\fR|\fB--regex\fR) [options] domain(s)
.br
\fBpihole\fR (\fB--allow-wild\fR|\fB--wild\fR) [options] domain(s)
.br
\fBpihole setpassword\fR password
.br
\fBpihole\fR \fB-d\fR [-a] [-c]
.br
\fBpihole -f
.br
pihole -r
.br
\fBpihole\fR \fB-t\fR [arg]
.br
\fBpihole -g\fR
.br
\fBpihole\fR \fB-q\fR [options]
.br
\fBpihole\fR \fB-l\fR (\fBon|off|off noflush\fR)
.br
\fBpihole -up \fR[--check-only]
.br
\fBpihole -v\fR
.br
\fBpihole uninstall\fR
.br
\fBpihole status\fR
.br
\fBpihole reloaddns\fR
.br
\fBpihole reloadlists\fR
.br
\fBpihole\fR (\fBenable\fR|\fBdisable\fR [time])
.br
\fBpihole\fR \fBcheckout\fR repo [branch]
.br
\fBpihole\fR \fBapi\fR [verbose] endpoint
.br
\fBpihole\fR \fBhelp\fR
.br
.SH "DESCRIPTION"
Available commands and options:
.br
\fBallow, allowlist\fR [options] [<domain1> <domain2 ...>]
.br
Adds or removes specified domain or domains to the Allowlist
.br
\fBdeny, denylist\fR [options] [<domain1> <domain2 ...>]
.br
Adds or removes specified domain or domains to the denylist
.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
\fB--wild, wildcard\fR [options] [<domain1> <domain2 ...>]
.br
Add or removes specified domain to the wildcard denylist
.br
\fB--allow-wild\fR [options] [<domain1> <domain2 ...>]
.br
Add or removes specified domain to the wildcard allowlist
.br
(Allow-/denylist manipulation options):
.br
not, -d, --delmode Remove domain(s) from the list
.br
-q, --quiet Make output less verbose
.br
-l, --list Display all your listed domains
.br
\fB-d, debug\fR [-a]
.br
Start a debugging session
.br
-a Enable automated debugging
-c Include a Pi-hole database integrity check
.br
\fB-f, flush\fR
.br
Flush the Pi-hole log
.br
\fB-r, reconfigure\fR
.br
Reconfigure or Repair Pi-hole subsystems
.br
\fB-t, tail\fR [arg]
.br
View the live output of the Pi-hole log
.br
[arg] Optional argument to filter the log for
(regular expressions are supported)
.br
\fB-g, updateGravity\fR
.br
Update the list of ad-serving domains
.br
\fB-q, query\fR [option]
.br
Query the adlists for a specified domain
.br
(Query options):
.br
-partial Search the adlists for partially matching domains
.br
-all Return all query matches within a adlists
.br
\fB-h, --help, help\fR
.br
Show a help dialog
.br
\fB-l, logging\fR [on|off|off noflush]
.br
Specify whether the Pi-hole log should be used
.br
(Logging options):
.br
on Enable the Pi-hole log at /var/log/pihole/pihole.log
.br
off Disable and flush the Pi-hole log at
/var/log/pihole/pihole.log
.br
off noflush Disable the Pi-hole log at /var/log/pihole/pihole.log
.br
\fB-up, updatePihole\fR [--check-only]
.br
Update Pi-hole subsystems
.br
--check-only Exit script before update is performed.
.br
\fB-v, version\fR
.br
Show installed versions of Pi-hole, Web Interface &amp; FTL
.br
\fBsetpassword\fR
.br
Set Web Interface password
.br
\fBuninstall\fR
.br
Uninstall Pi-hole from your system
.br
\fBstatus\fR
.br
Display the running status of Pi-hole subsystems
.br
\fBenable\fR [time]
.br
Enable Pi-hole blocking, optionally for a set duration
.br
\fBdisable\fR [time]
.br
Disable Pi-hole blocking, optionally for a set duration
.br
(time options):
.br
#s Disable Pi-hole functionality for # second(s)
.br
#m Disable Pi-hole functionality for # minute(s)
.br
\fBreloaddns\fR
.br
Update the lists and flush the cache without restarting the DNS server
.br
\fBreloadlists\fR
.br
Update the lists WITHOUT flushing the cache or restarting the DNS server
.br
\fBcheckout\fR [repo] [branch]
.br
Switch Pi-hole subsystems to a different GitHub branch
.br
(repo options):
.br
core Change the branch of Pi-hole's core subsystem
.br
web Change the branch of Admin Console subsystem
.br
ftl Change the branch of Pi-hole's FTL subsystem
.br
(branch options):
.br
master Update subsystems to the latest stable release
.br
dev Update subsystems to the latest development
release
.br
branchname Update subsystems to the specified branchname
.br
\fBapi\fR [verbose] endpoint
.br
Query the Pi-hole API at <endpoint>
.br
verbose Show authentication and status messages
.br
.SH "EXAMPLE"
Some usage examples
.br
Allow-/denylist manipulation
.br
\fBpihole allow iloveads.example.com\fR
.br
Allow "iloveads.example.com"
.br
\fBpihole deny remove noads.example.com\fR
.br
Removes "noads.example.com" from denylist
.br
\fBpihole --wild example.com\fR
.br
Adds example.com as a wildcard - would block all subdomains of
example.com, including example.com itself.
.br
\fBpihole --regex "ad.*\\.example\\.com$"\fR
.br
Adds "ad.*\\.example\\.com$" to the regex blacklist.
Would block all subdomains of example.com which start with "ad"
.br
Changing the Web Interface password
.br
\fBpihole setpassword ExamplePassword\fR
.br
Change the password to "ExamplePassword"
.br
Updating lists from internet sources
.br
\fBpihole -g\fR
.br
Update the list of ad-serving domains
.br
Displaying version information
.br
\fBpihole -v\fR
.br
Display the current version of Pi-hole
.br
Temporarily disabling Pi-hole
.br
\fBpihole disable 5m\fR
.br
Disable Pi-hole functionality for five minutes
.br
Switching Pi-hole subsystem branches
.br
\fBpihole checkout master\fR
.br
Switch to master branch
.br
\fBpihole checkout core dev\fR
.br
Switch to core development branch
.br
\fBpihole arpflush\fR
.br
Flush information stored in Pi-hole's network tables
.br
\fBpihole api stats/summary\fR
.br
Queries FTL for the stats/summary endpoint
.br
\fBpihole api verbose stats/summary\fR
.br
Same as above, but shows authentication and status messages
.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

660
pihole
View File

@@ -1,607 +1,121 @@
#!/usr/bin/env bash
#!/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.
#
# (c) 2015, 2016 by Jacob Salmela
# Network-wide ad blocking via your Raspberry Pi
# http://pi-hole.net
# Controller for all pihole scripts and functions.
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
# 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.
PI_HOLE_SCRIPT_DIR="/opt/pihole"
# PI_HOLE_BIN_DIR is not readonly here because in some functions (checkout),
# they might get set again when the installer is sourced. This causes an
# error due to modifying a readonly variable.
PI_HOLE_BIN_DIR="/usr/local/bin"
readonly colfile="${PI_HOLE_SCRIPT_DIR}/COL_TABLE"
# shellcheck source=./advanced/Scripts/COL_TABLE
source "${colfile}"
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck source=./advanced/Scripts/utils.sh
source "${utilsfile}"
# Source api functions
readonly apifile="${PI_HOLE_SCRIPT_DIR}/api.sh"
# shellcheck source=./advanced/Scripts/api.sh
source "${apifile}"
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}"
# Must be root to use this tool
if [[ ! $EUID -eq 0 ]];then
#echo "::: You are root."
#else
#echo "::: Sudo will be used for this tool."
# Check if it is actually installed
# If it isn't, exit because the pihole cannot be invoked without privileges.
if [[ $(dpkg-query -s sudo) ]];then
export SUDO="sudo"
else
echo "::: Please install sudo or run this as root."
exit 1
fi
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
function whitelistFunc {
shift
$SUDO /opt/pihole/whitelist.sh "$@"
exit 1
}
listFunc() {
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
exit 0
function blacklistFunc {
shift
$SUDO /opt/pihole/blacklist.sh "$@"
exit 1
}
debugFunc() {
local automated
local check_database_integrity
# Pull off the `debug` leaving passed call augmentation flags in $1
shift
for value in "$@"; do
[[ "$value" == *"-a"* ]] && automated="true"
[[ "$value" == *"-c"* ]] && check_database_integrity="true"
[[ "$value" == *"--check_database"* ]] && check_database_integrity="true"
done
AUTOMATED=${automated:-} CHECK_DATABASE=${check_database_integrity:-} "${PI_HOLE_SCRIPT_DIR}"/piholeDebug.sh
exit 0
function debugFunc {
$SUDO /opt/pihole/piholeDebug.sh
exit 1
}
flushFunc() {
"${PI_HOLE_SCRIPT_DIR}"/piholeLogFlush.sh "$@"
exit 0
function flushFunc {
$SUDO /opt/pihole/piholeLogFlush.sh
exit 1
}
arpFunc() {
"${PI_HOLE_SCRIPT_DIR}"/piholeARPTable.sh "$@"
exit 0
function updateDashboardFunc {
$SUDO /opt/pihole/updateDashboard.sh
exit 1
}
updatePiholeFunc() {
if [ -n "${DOCKER_VERSION}" ]; then
unsupportedFunc
else
shift
"${PI_HOLE_SCRIPT_DIR}"/update.sh "$@"
exit 0
fi
function updateGravityFunc {
$SUDO /opt/pihole/gravity.sh
exit 1
}
repairPiholeFunc() {
if [ -n "${DOCKER_VERSION}" ]; then
unsupportedFunc
else
/etc/.pihole/automated\ install/basic-install.sh --repair
exit 0;
fi
function updatePiholeFunc {
$SUDO /opt/pihole/updatePihole.sh
exit 1
}
updateGravityFunc() {
exec "${PI_HOLE_SCRIPT_DIR}"/gravity.sh "$@"
function setupLCDFunction {
$SUDO /opt/pihole/setupLCD.sh
exit 1
}
queryFunc() {
shift
"${PI_HOLE_SCRIPT_DIR}"/query.sh "$@"
exit 0
}
chronometerFunc() {
echo "Chronometer is gone, use PADD (https://github.com/pi-hole/PADD)"
exit 0
function chronometerFunc {
shift
$SUDO /opt/pihole/chronometer.sh "$@"
exit 1
}
uninstallFunc() {
if [ -n "${DOCKER_VERSION}" ]; then
unsupportedFunc
else
"${PI_HOLE_SCRIPT_DIR}"/uninstall.sh
exit 0
fi
function uninstallFunc {
$SUDO /opt/pihole/uninstall.sh
exit 1
}
versionFunc() {
exec "${PI_HOLE_SCRIPT_DIR}"/version.sh
}
reloadDNS() {
local svcOption svc str output status pid icon FTL_PID_FILE
svcOption="${1:-reload}"
# get the current path to the pihole-FTL.pid
FTL_PID_FILE="$(getFTLConfigValue files.pid)"
# Determine if we should reload or restart
if [[ "${svcOption}" =~ "reload-lists" ]]; then
# Reloading of the lists has been requested
# Note 1: This will NOT re-read any *.conf files
# Note 2: We cannot use killall here as it does
# not know about real-time signals
pid="$(getFTLPID ${FTL_PID_FILE})"
if [[ "$pid" -eq "-1" ]]; then
svc="true"
str="FTL is not running"
icon="${INFO}"
else
svc="kill -RTMIN ${pid}"
str="Reloading DNS lists"
icon="${TICK}"
fi
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
# Print output to Terminal, but not to Web Admin
[[ -t 1 ]] && echo -ne " ${INFO} ${str}..."
output=$( { ${svc}; } 2>&1 )
status="$?"
if [[ "${status}" -eq 0 ]]; then
[[ -t 1 ]] && echo -e "${OVER} ${icon} ${str}"
return 0
else
[[ ! -t 1 ]] && local OVER=""
echo -e "${OVER} ${CROSS} ${output}"
return 1
fi
}
piholeEnable() {
if [[ "${2}" == "-h" ]] || [[ "${2}" == "--help" ]]; then
echo "Usage: pihole enable/disable [time]
Example: 'pihole enable', or 'pihole disable 5m'
En- or disable Pi-hole subsystems
Time:
#s En-/disable Pi-hole functionality for # second(s)
#m En-/disable Pi-hole functionality for # minute(s)"
exit 0
fi
# Get timer
local tt="null"
if [[ $# -gt 1 ]]; then
local error=false
if [[ "${2}" == *"s" ]]; then
tt=${2%"s"}
if [[ ! "${tt}" =~ ^-?[0-9]+$ ]];then
local error=true
fi
elif [[ "${2}" == *"m" ]]; then
tt=${2%"m"}
if [[ "${tt}" =~ ^-?[0-9]+$ ]];then
tt=$((${tt}*60))
else
local error=true
fi
elif [[ -n "${2}" ]]; then
local error=true
fi
if [[ ${error} == true ]];then
echo -e " ${COL_RED}Unknown format for blocking timer!${COL_NC}"
echo -e " Try 'pihole disable --help' for more information."
exit 1
fi
fi
# Authenticate with the API
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}"
}
piholeLogging() {
shift
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
echo "Usage: pihole logging [options]
Example: 'pihole logging on'
Specify whether the Pi-hole log should be used
Options:
on Enable the Pi-hole log at /var/log/pihole/pihole.log
off Disable and flush the Pi-hole log at /var/log/pihole/pihole.log
off noflush Disable the Pi-hole log at /var/log/pihole/pihole.log"
exit 0
elif [[ "${1}" == "off" ]]; then
# Disable logging
setFTLConfigValue dns.queryLogging false
if [[ "${2}" != "noflush" ]]; then
# Flush logs
"${PI_HOLE_BIN_DIR}"/pihole -f
fi
echo -e " ${INFO} Disabling logging..."
local str="Logging has been disabled!"
elif [[ "${1}" == "on" ]]; then
# Enable logging
setFTLConfigValue dns.queryLogging true
echo -e " ${INFO} Enabling logging..."
local str="Logging has been enabled!"
else
echo -e " ${COL_RED}Invalid option${COL_NC}
Try 'pihole logging --help' for more information."
exit 1
fi
echo -e "${OVER} ${TICK} ${str}"
}
analyze_ports() {
local lv4 lv6 port=${1}
# FTL is listening at least on at least one port when this
# function is getting called
# Check individual address family/protocol combinations
# For a healthy Pi-hole, they should all be up (nothing printed)
lv4="$(ss --ipv4 --listening --numeric --tcp --udp src :${port})"
if grep -q "udp " <<< "${lv4}"; then
echo -e " ${TICK} UDP (IPv4)"
else
echo -e " ${CROSS} UDP (IPv4)"
fi
if grep -q "tcp " <<< "${lv4}"; then
echo -e " ${TICK} TCP (IPv4)"
else
echo -e " ${CROSS} TCP (IPv4)"
fi
lv6="$(ss --ipv6 --listening --numeric --tcp --udp src :${port})"
if grep -q "udp " <<< "${lv6}"; then
echo -e " ${TICK} UDP (IPv6)"
else
echo -e " ${CROSS} UDP (IPv6)"
fi
if grep -q "tcp " <<< "${lv6}"; then
echo -e " ${TICK} TCP (IPv6)"
else
echo -e " ${CROSS} TCP (IPv6)"
fi
echo ""
}
statusFunc() {
# Determine if there is pihole-FTL service is listening
local pid port ftl_pid_file block_status
ftl_pid_file="$(getFTLConfigValue files.pid)"
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
# Determine if Pi-hole's blocking is enabled
block_status=$(getFTLConfigValue dns.blocking.active)
if [ ${block_status} == "true" ]; then
case "${1}" in
"web") echo "$port";;
*) echo -e " ${TICK} Pi-hole blocking is enabled";;
esac
else
case "${1}" in
"web") echo 0;;
*) echo -e " ${CROSS} Pi-hole blocking is disabled";;
esac
fi
exit 0
}
tailFunc() {
# Warn user if Pi-hole's logging is disabled
local logging_enabled
logging_enabled=$(getFTLConfigValue dns.queryLogging)
if [[ "${logging_enabled}" != "true" ]]; then
echo " ${CROSS} Warning: Query logging is disabled"
fi
echo -e " ${INFO} Press Ctrl-C to exit"
# Get logfile path
LOGFILE=$(getFTLConfigValue files.log.dnsmasq)
readonly LOGFILE
# Strip date from each line
# Color blocklist/denylist/wildcard entries as red
# Color A/AAAA/DHCP strings as white
# Color everything else as gray
tail -f $LOGFILE | grep --line-buffered -- "${1}" | sed -E \
-e "s,($(date +'%b %d ')| dnsmasq\[[0-9]*\]),,g" \
-e "s,(.*(denied |gravity blocked ).*),${COL_RED}&${COL_NC}," \
-e "s,.*(query\\[A|DHCP).*,${COL_NC}&${COL_NC}," \
-e "s,.*,${COL_GRAY}&${COL_NC},"
exit 0
}
piholeCheckoutFunc() {
if [ -n "${DOCKER_VERSION}" ]; then
echo -e "${CROSS} Function not supported in Docker images"
echo "Please build a custom image following the steps at"
echo "https://github.com/pi-hole/docker-pi-hole?tab=readme-ov-file#building-the-image-locally"
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
}
tricorderFunc() {
local tricorder_token
if [[ ! -p "/dev/stdin" ]]; then
echo -e " ${INFO} Please do not call Tricorder directly"
exit 1
fi
tricorder_token=$(curl --silent --fail --show-error --upload-file "-" https://tricorder.pi-hole.net/upload < /dev/stdin 2>&1)
if [[ "${tricorder_token}" != "https://tricorder.pi-hole.net/"* ]]; then
echo -e "${CROSS} uploading failed, contact Pi-hole support for assistance."
# Log curl error (if available)
if [ -n "${tricorder_token}" ]; then
echo -e "${INFO} Error message: ${COL_RED}${tricorder_token}${COL_NC}\\n"
tricorder_token=""
fi
exit 1
fi
echo "Upload successful, your token is: ${COL_GREEN}${tricorder_token}${COL_NC}"
exit 0
}
updateCheckFunc() {
"${PI_HOLE_SCRIPT_DIR}"/updatecheck.sh "$@"
exit 0
}
unsupportedFunc(){
echo "Function not supported in Docker images"
exit 0
}
helpFunc() {
echo "Usage: pihole [options]
Example: 'pihole allow -h'
Add '-h' after specific commands for more information on usage
Domain Options:
allow, allowlist Allow domain(s)
deny, denylist Deny domain(s)
--regex, regex Regex deny domains(s)
--allow-regex Regex allow domains(s)
--wild, wildcard Wildcard deny domain(s)
--allow-wild Wildcard allow domain(s)
Add '-h' for more info on allow/deny usage
Debugging Options:
-d, debug Start a debugging session
Add '-c' or '--check-database' to include a Pi-hole database integrity check
Add '-a' to automatically upload the log to tricorder.pi-hole.net
-f, flush Flush 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:
setpassword [pwd] Set the password for the web interface
Without optional argument, password is read interactively.
When specifying a password directly, enclose it in single quotes.
-g, updateGravity Update the list of ad-serving domains
-h, --help, help Show this help dialog
-l, logging Specify whether the Pi-hole log should be used
Add '-h' for more info on logging usage
-q, query Query the adlists for a specified domain
Add '-h' for more info on query usage
-up, updatePihole Update Pi-hole subsystems
Add '--check-only' to exit script before update is performed.
-v, version Show installed versions of Pi-hole, Web Interface & FTL
uninstall Uninstall Pi-hole from your system
status Display the running status of Pi-hole subsystems
enable Enable Pi-hole subsystems
Add '-h' for more info on enable usage
disable Disable Pi-hole subsystems
Add '-h' for more info on disable usage
reloaddns Update the lists and flush the cache without restarting the DNS server
reloadlists Update the lists WITHOUT flushing the cache or restarting the DNS server
checkout Switch Pi-hole subsystems to a different GitHub branch
Add '-h' for more info on checkout usage
arpflush Flush information stored in Pi-hole's network tables";
exit 0
function helpFunc {
echo "::: Control all PiHole specific functions!"
echo ":::"
echo "::: Usage: pihole [options]"
printf ":::\tAdd -h after -w (whitelist), -b (blacklist), or -c (chronometer) for more information on usage\n"
echo ":::"
echo "::: Options:"
echo "::: -w, whitelist Whitelist domains"
echo "::: -b, blacklist Blacklist domains"
echo "::: -d, debug Start a debugging session if having trouble"
echo "::: -f, flush Flush the pihole.log file"
echo "::: -u, updateDashboard Update the web dashboard manually"
echo "::: -up, updatePihole Update the Pi-hole core files manually"
echo "::: -g, updateGravity Update the list of ad-serving domains"
echo "::: -s, setupLCD Automatically configures the Pi to use the 2.8 LCD screen to display stats on it"
echo "::: -c, chronometer Calculates stats and displays to an LCD"
echo "::: -h, help Show this help dialog"
echo "::: uninstall Uninstall Pi-Hole from your system!"
exit 1
}
if [[ $# = 0 ]]; then
helpFunc
fi
# functions that do not require sudo power
need_root=1
case "${1}" in
"-h" | "help" | "--help" ) helpFunc;;
"-v" | "version" ) versionFunc;;
"-c" | "chronometer" ) chronometerFunc "$@";;
"-q" | "query" ) queryFunc "$@";;
"status" ) statusFunc "$2";;
"tricorder" ) tricorderFunc;;
# we need to add all arguments that require sudo power to not trigger the * argument
"allow" | "allowlist" ) need_root=0;;
"deny" | "denylist" ) need_root=0;;
"--wild" | "wildcard" ) need_root=0;;
"--regex" | "regex" ) need_root=0;;
"--allow-regex" | "allow-regex" ) need_root=0;;
"--allow-wild" | "allow-wild" ) need_root=0;;
"-f" | "flush" ) ;;
"-up" | "updatePihole" ) ;;
"-r" | "repair" ) ;;
"-l" | "logging" ) ;;
"uninstall" ) ;;
"enable" ) need_root=0;;
"disable" ) need_root=0;;
"-d" | "debug" ) ;;
"-g" | "updateGravity" ) need_root=0;;
"reloaddns" ) ;;
"reloadlists" ) ;;
"setpassword" ) ;;
"checkout" ) ;;
"updatechecker" ) ;;
"arpflush" ) ;;
"-t" | "tail" ) ;;
"api" ) need_root=0;;
* ) helpFunc;;
esac
# In the case of alpine running in a container, the USER variable appears to be blank
# which prevents the next trap from working correctly. Set it by running whoami
if [[ -z ${USER} ]]; then
USER=$(whoami)
fi
# Check if the current user is not root and if the command
# requires root. If so, exit with an error message.
if [[ $EUID -ne 0 && need_root -eq 1 ]];then
echo -e " ${CROSS} The Pi-hole command requires root privileges, try:"
echo -e " ${COL_GREEN}sudo pihole $*${COL_NC}"
exit 1
helpFunc
fi
# Handle redirecting to specific functions based on arguments
case "${1}" in
"allow" | "allowlist" ) listFunc "$@";;
"deny" | "denylist" ) listFunc "$@";;
"--wild" | "wildcard" ) listFunc "$@";;
"--regex" | "regex" ) listFunc "$@";;
"--allow-regex" | "allow-regex" ) listFunc "$@";;
"--allow-wild" | "allow-wild" ) listFunc "$@";;
"-d" | "debug" ) debugFunc "$@";;
"-f" | "flush" ) flushFunc "$@";;
"-up" | "updatePihole" ) updatePiholeFunc "$@";;
"-r" | "repair" ) repairPiholeFunc;;
"-g" | "updateGravity" ) updateGravityFunc "$@";;
"-l" | "logging" ) piholeLogging "$@";;
"uninstall" ) uninstallFunc;;
"enable" ) piholeEnable true "$2";;
"disable" ) piholeEnable false "$2";;
"reloaddns" ) reloadDNS "reload";;
"reloadlists" ) reloadDNS "reload-lists";;
"setpassword" ) SetWebPassword "$@";;
"checkout" ) piholeCheckoutFunc "$@";;
"updatechecker" ) shift; updateCheckFunc "$@";;
"arpflush" ) arpFunc "$@";;
"-t" | "tail" ) tailFunc "$2";;
"api" ) shift; apiFunc "$@";;
* ) helpFunc;;
case "$1" in
"-w" | "whitelist" ) whitelistFunc "$@";;
"-b" | "blacklist" ) blacklistFunc "$@";;
"-d" | "debug" ) debugFunc;;
"-f" | "flush" ) flushFunc;;
"-u" | "updateDashboard" ) updateDashboardFunc;;
"-up" | "updatePihole" ) updatePiholeFunc;;
"-g" | "updateGravity" ) updateGravityFunc;;
"-s" | "setupLCD" ) setupLCDFunction;;
"-c" | "chronometer" ) chronometerFunc "$@";;
"-h" | "help" ) helpFunc;;
"uninstall" ) uninstallFunc;;
* ) helpFunc;;
esac

View File

@@ -1,25 +0,0 @@
# Recommended way to run tests
Make sure you have Docker and Python w/pip package manager.
From command line all you need to do is:
- `pip install 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.
## Alternative py.test method of running tests
You're responsible for setting up your virtual env and dependencies in this situation.
```
py.test -vv -n auto -m "build_stage"
py.test -vv -n auto -m "not build_stage"
```
The build_stage tests have to run first to create the docker images, followed by the actual tests which utilize said images. Unless you're changing your dockerfiles you shouldn't have to run the build_stage every time - but it's a good idea to rebuild at least once a day in case the base Docker images or packages change.
# 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 :)

View File

View File

@@ -1,19 +0,0 @@
FROM quay.io/centos/centos:stream10
# Disable SELinux
RUN echo "SELINUX=disabled" > /etc/selinux/config
RUN yum install -y --allowerasing curl git initscripts
ENV GITDIR=/etc/.pihole
ENV SCRIPTDIR=/opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $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 && \

View File

@@ -1,19 +0,0 @@
FROM quay.io/centos/centos:stream9
# Disable SELinux
RUN echo "SELINUX=disabled" > /etc/selinux/config
RUN yum install -y --allowerasing curl git initscripts
ENV GITDIR=/etc/.pihole
ENV SCRIPTDIR=/opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $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 && \

View File

@@ -1,16 +0,0 @@
FROM buildpack-deps:bullseye-scm
ENV GITDIR=/etc/.pihole
ENV SCRIPTDIR=/opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $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 && \

View File

@@ -1,16 +0,0 @@
FROM buildpack-deps:bookworm-scm
ENV GITDIR=/etc/.pihole
ENV SCRIPTDIR=/opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $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 && \

View File

@@ -1,17 +0,0 @@
FROM fedora:40
RUN dnf install -y git initscripts
ENV GITDIR=/etc/.pihole
ENV SCRIPTDIR=/opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $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 && \

View File

@@ -1,17 +0,0 @@
FROM fedora:41
RUN dnf install -y git initscripts
ENV GITDIR=/etc/.pihole
ENV SCRIPTDIR=/opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $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 && \

View File

@@ -1,17 +0,0 @@
FROM fedora:42
RUN dnf install -y git initscripts
ENV GITDIR=/etc/.pihole
ENV SCRIPTDIR=/opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $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 && \

View File

@@ -1,16 +0,0 @@
FROM buildpack-deps:focal-scm
ENV GITDIR=/etc/.pihole
ENV SCRIPTDIR=/opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $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 && \

View File

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

View File

@@ -1,17 +0,0 @@
FROM buildpack-deps:24.04-scm
ENV GITDIR=/etc/.pihole
ENV SCRIPTDIR=/opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $GITDIR/advanced/Scripts/COL_TABLE $SCRIPTDIR/
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
ENV DEBIAN_FRONTEND=noninteractive
RUN true && \
chmod +x $SCRIPTDIR/*
ENV 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