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
56 changed files with 2918 additions and 9105 deletions

View File

@@ -1,38 +0,0 @@
# EditorConfig is awesome: http://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 = 2
charset = utf-8
trim_trailing_whitespace = true
# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,py}]
charset = utf-8
# 4 space indentation
[*.py]
indent_style = space
indent_size = 4
# Tab indentation (no size specified)
[Makefile]
indent_style = tab
# Indentation override for all JS under lib directory
[scripts/**.js]
indent_style = space
indent_size = 2
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

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

View File

@@ -1,37 +1,7 @@
**In raising this issue, I confirm the following:** `{please fill the checkboxes, e.g: [X]}`
##### Expected Behaviour:
- [] I have read and understood the [contributors guide](https://github.com/pi-hole/pi-hole/blob/master/CONTRIBUTING.md).
- [] The issue I am reporting can be *replicated*.
- [] The issue I am reporting isn't a duplicate (see [FAQs](https://github.com/pi-hole/pi-hole/wiki/FAQs), [closed issues](https://github.com/pi-hole/pi-hole/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), and [open issues](https://github.com/pi-hole/pi-hole/issues)).
**How familiar are you with the the source code relevant to this issue?:**
##### Actual Behaviour:
`{Replace this with a number from 1 to 10. 1 being not familiar, and 10 being very familiar}`
---
**Expected behaviour:**
`{A detailed description of what you expect to see}`
**Actual behaviour:**
`{A detailed description and/or screenshots of what you do see}`
**Steps to reproduce:**
`{Detailed steps of how we can reproduce this}`
**Debug token provided by [uploading `pihole -d` log](https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#debug):**
`{Alphanumeric token}`
**Troubleshooting undertaken, and/or other relevant information:**
`{Steps of what you have done to fix this}`
> * `{Please delete this quoted section when opening your issue}`
> * You must follow the template instructions. Failure to do so will result in your issue being closed.
> * Please [submit any feature requests here](https://discourse.pi-hole.net/c/feature-requests), so it is votable and trackable by the community.
> * Please respect that Pi-hole is developed by volunteers, who can only reply in their spare time.
> * Detail helps us understand and resolve an issue quicker, but please ensure it's relevant.
> * _This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._
##### Steps to reproduce this issue:

View File

@@ -1,32 +1,11 @@
**By submitting this pull request, I confirm the following:** `{please fill any appropriate checkboxes, e.g: [X]}`
Fixes #[issue number] .
`{Please ensure that your pull request is for the 'development' branch!}`
Changes proposed in this pull request:
- [] I have read and understood the [contributors guide](https://github.com/pi-hole/pi-hole/blob/master/CONTRIBUTING.md), as well as this entire template.
- [] I have made only one major change in my proposed changes.
- [] I have commented my proposed changes within the code.
- [] I have tested my proposed changes, and have included unit tests where possible.
- [] I am willing to help maintain this change if there are issues with it later.
- [] I give this submission freely and claim no ownership.
- [] It is compatible with the [EUPL 1.2 license](https://opensource.org/licenses/EUPL-1.1)
- [] I have squashed any insignificant commits. ([`git rebase`](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html))
- [] I have Signed Off all commits. ([`git commit --signoff`](https://git-scm.com/docs/git-commit#git-commit---signoff))
-
---
-
**What does this PR aim to accomplish?:**
-
`{A detailed description, screenshots (if necessary), as well as links to any relevant GitHub issues}`
**How does this PR accomplish the above?:**
`{A detailed description (such as a changelog) and screenshots (if necessary) of the implemented fix}`
**What documentation changes (if any) are needed to support this PR?:**
`{A detailed list of any necessary changes}`
> * `{Please delete this quoted section when opening your pull request}`
> * You must follow the template instructions. Failure to do so will result in your issue being closed.
> * Please respect that Pi-hole is developed by volunteers, who can only reply in their spare time.
> * Detail helps us understand an issue quicker, but please ensure it's relevant.
@pi-hole/gravity

4
.gitignore vendored
View File

@@ -1,5 +1 @@
.DS_Store
*.pyc
*.swp
__pycache__
.cache

View File

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

View File

@@ -1,38 +0,0 @@
version: 2
always_pending:
title_regex: '(WIP|wip)'
labels:
- wip
explanation: 'This PR is a work in progress...'
group_defaults:
reset_on_push:
enabled: true
reject_value: -2
approve_regex: '^(Approved|:shipit:|:\+1:|Engage|:taco:)'
reject_regex: '^(Rejected|:-1:|Borg)'
author_approval:
auto: true
groups:
development:
approve_by_comment:
enabled: true
conditions:
branches:
- development
required: 2
teams:
- approvers
master:
approve_by_comment:
enabled: true
conditions:
branches:
- master
required: 4
teams:
- approvers

View File

@@ -1,3 +0,0 @@
linters:
shellcheck:
shell: bash

View File

@@ -1,10 +0,0 @@
sudo: required
services:
- docker
language: python
python:
- "2.7"
install:
- pip install -r requirements.txt
script: py.test -vv

View File

@@ -1,39 +1,8 @@
_This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._
This is a basic checklist for now, We will update it in the future.
# Contributors Guide
Please read and understand the contribution guide before creating an issue or pull request.
## Etiquette
- Our goal for Pi-hole is **stability before features**. This means we focus on squashing critical bugs before adding new features. Often, we can do both in tandem, but bugs will take priority over a new feature.
- Pi-hole is open source and [powered by donations](https://pi-hole.net/donate/), and as such, we give our **free time** to build, maintain, and **provide user support** for this project. It would be extremely unfair for us to suffer abuse or anger for our hard work, so please take a moment to consider that.
- Please be considerate towards the developers and other users when raising issues or presenting pull requests.
- Respect our decision(s), and do not be upset or abusive if your submission is not used.
## Viability
When requesting or submitting new features, first consider whether it might be useful to others. Open source projects are used by many people, who may have entirely different needs to your own. Think about whether or not your feature is likely to be used by other users of the project.
## Procedure
**Before filing an issue:**
- Attempt to replicate and **document** the problem, to ensure that it wasn't a coincidental incident.
- Check to make sure your feature suggestion isn't already present within the project.
- Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
- Check the pull requests tab to ensure that the feature isn't already in progress.
**Before submitting a pull request:**
- Check the codebase to ensure that your feature doesn't already exist.
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
## Technical Requirements
- Submit Pull Requests to the **development branch only**.
- Before Submitting your Pull Request, merge `development` with your new branch and fix any conflicts. (Make sure you don't break anything in development!)
- Please use the [Google Style Guide for Shell](https://google.github.io/styleguide/shell.xml) for your code submission styles.
- Commit Unix line endings.
- Please use the Pi-hole brand: **Pi-hole** (Take a special look at the capitalized 'P' and a low 'h' with a hyphen)
- (Optional fun) keep to the theme of Star Trek/black holes/gravity.
* 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.

286
README.md
View File

@@ -1,217 +1,111 @@
<p align="center">
<a href="https://pi-hole.net"><img src="https://pi-hole.github.io/graphics/Vortex/Vortex_with_text.png" width="150" height="255" alt="Pi-hole"></a><br/>
<b>Network-wide ad blocking via your own Linux hardware</b><br/>
</p>
# Automated Install
##### Designed For Raspberry Pi A+, B, B+, 2, Zero, and 3B (with an Ethernet/Wi-Fi adapter) (Works on most Debian distributions!)
The Pi-hole is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content, without installing any client-side software.
- **Easy-to-install**: our versatile installer walks you through the process, and [takes less than ten minutes](https://www.youtube.com/watch?v=vKWjx1AQYgs)
- **Resolute**: content is blocked in _non-browser locations_, such as ad-laden mobile apps and smart TVs
- **Responsive**: seamlessly speeds up the feel of everyday browsing by caching DNS queries
- **Lightweight**: runs smoothly with [minimal hardware and software requirements](https://discourse.pi-hole.net/t/hardware-software-requirements/273)
- **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 which helps ensure _you_ are the sole person in control of your privacy
[![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)
-----
<a href="https://www.codacy.com/app/Pi-hole/pi-hole?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=pi-hole/pi-hole&amp;utm_campaign=Badge_Grade"><img src="https://api.codacy.com/project/badge/Grade/c558a0f8d7124c99b02b84f0f5564238" alt="Codacy Grade"/></a>
<a href="https://travis-ci.org/pi-hole/pi-hole"><img src="https://travis-ci.org/pi-hole/pi-hole.svg?branch=development" alt="Travis Build Status"/></a>
<a href="https://www.bountysource.com/trackers/3011939-pi-hole-pi-hole?utm_source=3011939&utm_medium=shield&utm_campaign=TRACKER_BADGE"><img src="https://www.bountysource.com/badge/tracker?tracker_id=3011939" alt="BountySource"/></a>
1. Install Raspbian
## One-Step Automated Install
Those who want to get started quickly and conveniently, may install Pi-hole using the following command:
2. Run the command below
#### `curl -sSL https://install.pi-hole.net | bash`
### ```curl -L https://install.pi-hole.net | bash```
## 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
```
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
#### Alternative Semi-Automated install ####
```
wget -O basic-install.sh https://install.pi-hole.net
sudo bash basic-install.sh
chmod +x basic-install.sh
./basic-install.sh
```
## Post-install: Make your network take advantage of 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/).
Once the installer has been run, you will need to [configure your router to have **DHCP clients use Pi-hole as their DNS server**](https://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245) which ensures that all devices connecting to your network will have content blocked without any further intervention.
## 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")
If your router does not support setting the DNS server, you can [use Pi-hole's built in DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026); just be sure to disable DHCP on your router first (if it has that feature available).
## Catch us out on the net:
Twitter: [@The_Pi_Hole](https://twitter.com/The_Pi_Hole)
As a last resort, you can always manually set each device to use Pi-hole as their DNS server.
reddit: [/r/pihole](https://www.reddit.com/r/pihole/)
-----
## How Does It Work?
**Watch the 60-second video below to get a quick overview**
## Pi-hole is free, but powered by your support
There are many reoccurring costs involved with maintaining free, open source, and privacy respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software, as well as the importance of keeping it maintained.
Make no mistake: **your support is absolutely vital to help keep us innovating!**
### Donations
Sending a donation using our links below is **extremely helpful** in offsetting a portion of our monthly expenses:
&nbsp;<img src="https://pi-hole.github.io/graphics/Badges/paypal-badge-black.svg" width="24" height="24" alt="PP"/> <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY">Donate via PayPal</a><br/>
&nbsp;<img src="https://pi-hole.github.io/graphics/Badges/bitcoin-badge-black.svg" width="24" height="24" alt="BTC"/> Bitcoin Address: <code>1GKnevUnVaQM2pQieMyeHkpr8DXfkpfAtL</code>
### Alternative support
If you'd rather not donate (_which is okay!_), there are other ways you can help support us:
- [Digital Ocean](http://www.digitalocean.com/?refcode=344d234950e1) affiliate link
- [Vultr](http://www.vultr.com/?ref=7190426) affiliate link
- [UNIXstickers.com](http://unixstickers.refr.cc/jacobs) affiliate link
- [Pi-hole Swag Store](https://pi-hole.net/shop/)
- Spreading the word about our software, and how you have benefited from it
### Contributing via GitHub
We welcome _everyone_ to contribute to issue reports, suggest new features, and create pull requests.
If you have something to add - anything from a typo through to a whole new feature, we're happy to check it out! Just make sure to fill out our template when submitting your request; the questions that it asks will help the volunteers quickly understand what you're aiming to achieve.
You'll find that the [install script](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) and the [debug script](https://github.com/pi-hole/pi-hole/blob/master/advanced/Scripts/piholeDebug.sh) have an abundance of comments, which will help you better understand how Pi-hole works. They're also a valuable resource to those who want to learn how to write scripts or code a program! We encourage anyone who likes to tinker to read through it, and submit a pull request for us to review.
### Presentations about Pi-hole
Word-of-mouth continues to help our project grow immensely, and so we are helping make this easier for people.
If you are going to be presenting Pi-hole at a conference, meetup or even a school project, [get in touch with us](https://pi-hole.net/2017/05/17/giving-a-presentation-on-pi-hole-contact-us-first-for-some-goodies-and-support/) so we can hook you up with free swag to hand out to your audience!
-----
## Getting in touch with us
While we are primarily reachable on our <a href="https://discourse.pi-hole.net/">Discourse User Forum</a>, we can also be found on a variety of social media outlets. **Please be sure to check the FAQ's** before starting a new discussion, as we do not have the spare time to reply to every request for assistance.
<ul>
<li><a href="https://discourse.pi-hole.net/c/faqs">Frequently Asked Questions</a></li>
<li><a href="https://github.com/pi-hole/pi-hole/wiki">Pi-hole Wiki</a></li>
<li><a href="https://discourse.pi-hole.net/c/feature-requests?order=votes">Feature Requests</a></li>
</ul>
<br/>
<ul>
<li><a href="https://discourse.pi-hole.net/">Discourse User Forum</a></li>
<li><a href="https://www.reddit.com/r/pihole/">Reddit</a></li>
<li><a href="https://gitter.im/pi-hole/pi-hole">Gitter</a> (Real-time chat)</li>
<li><a href="https://twitter.com/The_Pi_Hole">Twitter</a></li>
<li><a href="https://www.youtube.com/channel/UCT5kq9w0wSjogzJb81C9U0w">YouTube</a></li>
<li><a href="https://www.facebook.com/ThePiHole/">Facebook</a></li>
</ul>
-----
## Breakdown of Features
### The Command Line Interface
The `pihole` command has all the functionality necessary to be able to fully administer the Pi-hole, without the need of the Web Interface. It's fast, user-friendly, and auditable by anyone with understanding of `bash`.
<a href="https://pi-hole.github.io/graphics/Screenshots/blacklist-cli.gif"><img src="https://pi-hole.github.io/graphics/Screenshots/blacklist-cli.gif" alt="Pi-hole Blacklist Demo"/></a>
Some notable features include:
* [Whitelisting, Blacklisting and Wildcards](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#whitelisting-blacklisting-and-wildcards)
* [Debugging utility](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#debugger)
* [Viewing the live log file](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#tail)
* [Real-time Statistics via `ssh`](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#chronometer) or [your TFT LCD screen](http://www.amazon.com/exec/obidos/ASIN/B00ID39LM4/pihole09-20)
* [Updating Ad Lists](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#gravity)
* [Querying Ad Lists for blocked domains](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#query)
* [Enabling and Disabling Pi-hole](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown#enable--disable)
* ... and *many* more!
You can read our [Core Feature Breakdown](https://github.com/pi-hole/pi-hole/wiki/Core-Function-Breakdown), as well as read up on [example usage](https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738) for more information.
### The Web Interface Dashboard
This [optional dashboard](https://github.com/pi-hole/AdminLTE) allows you to view stats, change settings, and configure your Pi-hole. It's the power of the Command Line Interface, with none of the learning curve!
<a href="https://pi-hole.github.io/graphics/Screenshots/dashboard.png"><img src="https://pi-hole.github.io/graphics/Screenshots/dashboard.png" width="888" height="522" alt="Pi-hole Dashboard"/></a>
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://<IP_ADDPRESS_OF_YOUR_PI_HOLE>/admin/`
2. `http:/pi.hole/admin/` (when using Pi-hole as your DNS server)
3. `http://pi.hole/` (when using Pi-hole as your DNS server)
## The Faster-Than-Light Engine
The [FTL Engine](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, FTL does this all *very quickly*!
Some of the statistics you can integrate include:
* Total number of domains being blocked
* Total number of DNS queries today
* Total number of ads blocked today
* Percentage of ads blocked
* Unique domains
* Queries forwarded (to your chosen upstream DNS server)
* Queries cached
* Unique clients
The API can be accessed via [`telnet`](https://github.com/pi-hole/FTL), the Web (`admin/api.php`) and Command Line (`pihole -c -j`). You can out find [more details over here](https://discourse.pi-hole.net/t/pi-hole-api/1863).
-----
## The Origin Of Pi-hole
Pi-hole being a **advertising-aware DNS/Web server**, makes use of the following technologies:
* [`dnsmasq`](http://www.thekelleys.org.uk/dnsmasq/doc.html) - a lightweight DNS and DHCP server
* [`curl`](https://curl.haxx.se) - A command line tool for transferring data with URL syntax
* [`lighttpd`](https://www.lighttpd.net) - webserver designed and optimized for high performance
* [`php`](https://secure.php.net) - a popular general-purpose web scripting language
* [AdminLTE Dashboard](https://github.com/almasaeed2010/AdminLTE) - premium admin control panel based on Bootstrap 3.x
While quite outdated at this point, [this original blog post about Pi-hole](https://jacobsalmela.com/2015/06/16/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0/) goes into **great detail** about how Pi-hole was originally setup and how it works. Syntactically, it's no longer accurate, but the same basic principles and logic still apply to Pi-hole's current state.
-----
[![Pi-hole exlplained](http://i.imgur.com/qNybJDX.png)](https://vimeo.com/135965232)
## Pi-hole Projects
- [The Big Blocklist Collection](https://wally3k.github.io)
- [Docker Pi-hole container (x86 and ARM)](https://hub.docker.com/r/diginc/pi-hole/)
- [Pi-Hole in the cloud](http://blog.codybunch.com/2015/07/28/Pi-Hole-in-the-cloud/)
- [Pie in the Sky-Hole [A Pi-Hole in the cloud for ad-blocking via DNS]](https://dlaa.me/blog/post/skyhole)
- [Pi-hole Enable/Disable Button](http://thetimmy.silvernight.org/pages/endisbutton/)
- [Minibian Pi-hole](https://munkjensen.net/wiki/index.php/See_my_Pi-Hole#Minibian_Pi-hole)
- [CHiP-hole: Network-wide Ad-blocker](https://www.hackster.io/jacobsalmela/chip-hole-network-wide-ad-blocker-98e037)
- [Chrome Extension: Pi-Hole List Editor](https://chrome.google.com/webstore/detail/pi-hole-list-editor/hlnoeoejkllgkjbnnnhfolapllcnaglh) ([Source Code](https://github.com/packtloss/pihole-extension))
- [Splunk: Pi-hole Visualiser](https://splunkbase.splunk.com/app/3023/)
- [Adblocking with P-hole and Ubuntu 14.04 on VirtualBox](https://hbalagtas.blogspot.com.au/2016/02/adblocking-with-pi-hole-and-ubuntu-1404.html)
- [Pi-hole stats in your Mac's menu bar](https://getbitbar.com/plugins/Network/pi-hole.1m.py)
- [Pi-hole unRAID Template](https://forums.lime-technology.com/topic/36810-support-spants-nodered-mqtt-dashing-couchdb/)
- [Copernicus: Windows Tray Application](https://github.com/goldbattle/copernicus)
- [Let your blink1 device blink when Pi-hole filters ads](https://gist.github.com/elpatron68/ec0b4c582e5abf604885ac1e068d233f)
- [Pi-hole metrics](https://github.com/nlamirault/pihole_exporter) exporter for [Prometheus](https://prometheus.io/)
- [Magic Mirror with DNS Filtering](https://zonksec.com/blog/magic-mirror-dns-filtering/#dnssoftware)
- [Pi-hole Droid: Android client](https://github.com/friimaind/pi-hole-droid)
-----
- [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)
## Coverage
- [Lifehacker: Turn A Raspberry Pi Into An Ad Blocker With A Single Command](https://www.lifehacker.com.au/2015/02/turn-a-raspberry-pi-into-an-ad-blocker-with-a-single-command/)
- [MakeUseOf: Adblock Everywhere: The Raspberry Pi-Hole Way](http://www.makeuseof.com/tag/adblock-everywhere-raspberry-pi-hole-way/)
- [Catchpoint: Ad-Blocking on Apple iOS9: Valuing the End User Experience](http://blog.catchpoint.com/2015/09/14/ad-blocking-apple/)
- [Security Now Netcast: Pi-hole](https://www.youtube.com/watch?v=p7-osq_y8i8&t=100m26s)
- [TekThing: Raspberry Pi-Hole Makes Ads Disappear!](https://youtu.be/8Co59HU2gY0?t=2m)
- [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)
- [Block Ads on All Home Devices for $53.18](https://medium.com/@robleathern/block-ads-on-all-home-devices-for-53-18-a5f1ec139693#.gj1xpgr5d)
- [Pi-Hole for Ubuntu 14.04](http://www.boyter.org/2015/12/pi-hole-ubuntu-14-04/)
- [MacObserver Podcast 585](https://www.macobserver.com/tmo/podcast/macgeekgab-585)
- [The Defrag Show: Endoscope USB Camera, The Final [HoloLens] Vote, Adblock Pi and more](https://channel9.msdn.com/Shows/The-Defrag-Show/Defrag-Endoscope-USB-Camera-The-Final-HoloLens-Vote-Adblock-Pi-and-more?WT.mc_id=dlvr_twitter_ch9#time=20m39s)
- [Adafruit: Pi-hole is a black hole for internet ads](https://blog.adafruit.com/2016/03/04/pi-hole-is-a-black-hole-for-internet-ads-piday-raspberrypi-raspberry_pi/)
- [Digital Trends: 5 Fun, Easy Projects You Can Try With a $35 Raspberry Pi](https://youtu.be/QwrKlyC2kdM?t=1m42s)
- [Adafruit: Raspberry Pi Quick Look at Pi Hole ad blocking server with Tony D](https://www.youtube.com/watch?v=eg4u2j1HYlI)
- [Devacron: OrangePi Zero as an Ad-Block server with Pi-Hole](http://www.devacron.com/orangepi-zero-as-an-ad-block-server-with-pi-hole/)
- [Linux Pro: The Hole Truth](http://www.linuxpromagazine.com/Issues/2017/200/The-sysadmin-s-daily-grind-Pi-hole)
- [CryptoAUSTRALIA: How We Tried 5 Privacy Focused Raspberry Pi Projects](https://blog.cryptoaustralia.org.au/2017/10/05/5-privacy-focused-raspberry-pi-projects/)
- [CryptoAUSTRALIA: Pi-hole Workshop](https://blog.cryptoaustralia.org.au/2017/11/02/pi-hole-network-wide-ad-blocker/)
- [Know How 355: Killing ads with a Raspberry Pi-Hole!](https://www.twit.tv/shows/know-how/episodes/355)
- [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/)
## Partnering With Optimal.com
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/).
## Technical Details
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.
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).
## 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)).
## 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
## 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:
`http://192.168.1.x/admin/index.php`
![Pi-hole Advanced Stats Dashboard](http://i.imgur.com/rTlLYPh.png)
### 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`
![Web](http://i.imgur.com/m114SCn.png)
## Real-time Statistics
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)
## 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)
## 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.

View File

@@ -1,23 +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
##StevenBlack's list
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
##MalwareDomains
https://mirror1.malwaredomains.com/files/justdomains
##Cameleon
# Other lists we consider safe:
http://adblock.gjtech.net/?format=unix-hosts
http://mirror1.malwaredomains.com/files/justdomains
http://sysctl.org/cameleon/hosts
##Zeustracker
https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist
##Disconnect.me Tracking
https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
##Disconnect.me Ads
https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt
##Hosts-file.net
https://hosts-file.net/ad_servers.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

View File

@@ -9,39 +9,53 @@
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
###############################################################################
# FILE AUTOMATICALLY POPULATED BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
# #
# IF YOU WISH TO CHANGE THE UPSTREAM SERVERS, CHANGE THEM IN: #
# /etc/pihole/setupVars.conf #
# #
# ANY OTHER CHANGES SHOULD BE MADE IN A SEPERATE CONFIG FILE #
# OR IN /etc/dnsmasq.conf #
###############################################################################
# If you want dnsmasq to read another file, as well as /etc/hosts, use
# this.
addn-hosts=/etc/pihole/gravity.list
addn-hosts=/etc/pihole/black.list
addn-hosts=/etc/pihole/local.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
localise-queries
# 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
local-ttl=2
# 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

View File

@@ -1,49 +0,0 @@
# Determine if terminal is capable of showing colours
if [[ -t 1 ]] && [[ $(tput colors) -ge 8 ]]; then
# Bold and underline may not show up on all clients
# If something MUST be emphasised, use both
COL_BOLD=''
COL_ULINE=''
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_ULINE=""
COL_NC=""
COL_GRAY=""
COL_RED=""
COL_GREEN=""
COL_YELLOW=""
COL_BLUE=""
COL_PURPLE=""
COL_CYAN=""
fi
# Deprecated variables
COL_WHITE="${COL_BOLD}"
COL_BLACK="${COL_NC}"
COL_LIGHT_BLUE="${COL_BLUE}"
COL_LIGHT_GREEN="${COL_GREEN}"
COL_LIGHT_CYAN="${COL_CYAN}"
COL_LIGHT_RED="${COL_RED}"
COL_URG_RED="${COL_RED}${COL_BOLD}${COL_ULINE}"
COL_LIGHT_PURPLE="${COL_PURPLE}"
COL_BROWN="${COL_YELLOW}"
COL_LIGHT_GRAY="${COL_GRAY}"
COL_DARK_GRAY="${COL_GRAY}"
TICK="[${COL_GREEN}✓${COL_NC}]"
CROSS="[${COL_RED}✗${COL_NC}]"
INFO="[i]"
QST="[?]"
DONE="${COL_GREEN} done!${COL_NC}"
OVER="\\r"

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

View File

@@ -1,573 +1,148 @@
#!/usr/bin/env bash
# shellcheck disable=SC1090,SC1091
# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# (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
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
LC_NUMERIC=C
# 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.
# Retrieve stats from FTL engine
pihole-FTL() {
ftl_port=$(cat /var/run/pihole-FTL.port 2> /dev/null)
if [[ -n "$ftl_port" ]]; then
# Open connection to FTL
exec 3<>"/dev/tcp/localhost/$ftl_port"
# Test if connection is open
if { "true" >&3; } 2> /dev/null; then
# Send command to FTL
echo -e ">$1" >&3
#Functions##############################################################################################################
piLog="/var/log/pihole.log"
gravity="/etc/pihole/gravity.list"
# Read input
read -r -t 1 LINE <&3
until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do
echo "$LINE" >&1
read -r -t 1 LINE <&3
done
today=$(date "+%b %e")
# Close connection
exec 3>&-
exec 3<&-
fi
else
echo "0"
fi
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
}
# Print spaces to align right-side additional text
printFunc() {
local text_last
title="$1"
title_len="${#title}"
text_main="$2"
text_main_nocol="$text_main"
if [[ "${text_main:0:1}" == "" ]]; then
text_main_nocol=$(sed 's/\[[0-9;]\{1,5\}m//g' <<< "$text_main")
fi
text_main_len="${#text_main_nocol}"
text_addn="$3"
if [[ "$text_addn" == "last" ]]; then
text_addn=""
text_last="true"
fi
# If there is additional text, define max length of text_main
if [[ -n "$text_addn" ]]; then
case "$scr_cols" in
[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-4]) text_main_max_len="9";;
4[5-9]) text_main_max_len="14";;
*) text_main_max_len="19";;
esac
fi
[[ -z "$text_addn" ]] && text_main_max_len="$(( scr_cols - title_len ))"
# Remove excess characters from main text
if [[ "$text_main_len" -gt "$text_main_max_len" ]]; then
# Trim text without colours
text_main_trim="${text_main_nocol:0:$text_main_max_len}"
# Replace with trimmed text
text_main="${text_main/$text_main_nocol/$text_main_trim}"
fi
# Determine amount of spaces for each line
if [[ -n "$text_last" ]]; then
# Move cursor to end of screen
spc_num=$(( scr_cols - ( title_len + text_main_len ) ))
else
spc_num=$(( text_main_max_len - text_main_len ))
fi
[[ "$spc_num" -le 0 ]] && spc_num="0"
spc=$(printf "%${spc_num}s")
#spc="${spc// /.}" # Debug: Visualise spaces
printf "%s%s$spc" "$title" "$text_main"
if [[ -n "$text_addn" ]]; then
printf "%s(%s)%s\\n" "$COL_NC$COL_DARK_GRAY" "$text_addn" "$COL_NC"
else
# Do not print trailing newline on final line
[[ -z "$text_last" ]] && printf "%s\\n" "$COL_NC"
fi
function CalcQueriesToday(){
if [ -e "$piLog" ];then
queriesToday=$(cat "$piLog" | grep "$today" | awk '/query/ {print $6}' | wc -l)
else
queriesToday="Err."
fi
}
# Perform on first Chrono run (not for JSON formatted string)
get_init_stats() {
calcFunc(){ awk "BEGIN {print $*}" 2> /dev/null; }
# Convert bytes to human-readable format
hrBytes() {
awk '{
num=$1;
if(num==0) {
print "0 B"
} else {
xxx=(num<0?-num:num)
sss=(num<0?-1:1)
split("B KB MB GB TB PB",type)
for(i=5;yyy < 1;i--) {
yyy=xxx / (2^(10*i))
}
printf "%.0f " type[i+2], yyy*sss
}
}' <<< "$1";
}
# Convert seconds to human-readable format
hrSecs() {
day=$(( $1/60/60/24 )); hrs=$(( $1/3600%24 ))
mins=$(( ($1%3600)/60 )); secs=$(( $1%60 ))
[[ "$day" -ge "2" ]] && plu="s"
[[ "$day" -ge "1" ]] && days="$day day${plu}, " || days=""
printf "%s%02d:%02d:%02d\\n" "$days" "$hrs" "$mins" "$secs"
}
# Set Colour Codes
coltable="/opt/pihole/COL_TABLE"
if [[ -f "${coltable}" ]]; then
source ${coltable}
else
COL_NC=""
COL_DARK_GRAY=""
COL_LIGHT_GREEN=""
COL_LIGHT_BLUE=""
COL_LIGHT_RED=""
COL_YELLOW=""
COL_LIGHT_RED=""
COL_URG_RED=""
fi
# Get RPi throttle state (RPi 3B only) & model number, or OS distro info
if command -v vcgencmd &> /dev/null; then
local sys_throttle_raw
local sys_rev_raw
sys_throttle_raw=$(vgt=$(sudo vcgencmd get_throttled); echo "${vgt##*x}")
# Active Throttle Notice: http://bit.ly/2gnunOo
if [[ "$sys_throttle_raw" != "0" ]]; then
case "$sys_throttle_raw" in
*0001) thr_type="${COL_YELLOW}Under Voltage";;
*0002) thr_type="${COL_LIGHT_BLUE}Arm Freq Cap";;
*0003) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC";;
*0004) thr_type="${COL_LIGHT_RED}Throttled";;
*0005) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
*0006) thr_type="${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
*0007) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
esac
[[ -n "$thr_type" ]] && sys_throttle="$thr_type${COL_DARK_GRAY}"
fi
sys_rev_raw=$(awk '/Revision/ {print $3}' < /proc/cpuinfo)
case "$sys_rev_raw" in
000[2-6]) sys_model=" 1, Model B";; # 256MB
000[7-9]) sys_model=" 1, Model A";; # 256MB
000d|000e|000f) sys_model=" 1, Model B";; # 512MB
0010|0013) sys_model=" 1, Model B+";; # 512MB
0012|0015) sys_model=" 1, Model A+";; # 256MB
a0104[0-1]|a21041|a22042) sys_model=" 2, Model B";; # 1GB
900021) sys_model=" 1, Model A+";; # 512MB
900032) sys_model=" 1, Model B+";; # 512MB
90009[2-3]|920093) sys_model=" Zero";; # 512MB
9000c1) sys_model=" Zero W";; # 512MB
a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB
*) sys_model="";;
esac
sys_type="Raspberry Pi$sys_model"
else
source "/etc/os-release"
CODENAME=$(sed 's/[()]//g' <<< "${VERSION/* /}")
sys_type="${NAME/ */} ${CODENAME^} $VERSION_ID"
fi
# Get core count
sys_cores=$(grep -c "^processor" /proc/cpuinfo)
# Test existence of clock speed file for ARM CPU
if [[ -f "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]]; then
scaling_freq_file="/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
fi
# Test existence of temperature file
if [[ -f "/sys/class/thermal/thermal_zone0/temp" ]]; then
temp_file="/sys/class/thermal/thermal_zone0/temp"
elif [[ -f "/sys/class/hwmon/hwmon0/temp1_input" ]]; then
temp_file="/sys/class/hwmon/hwmon0/temp1_input"
else
temp_file=""
fi
# Test existence of setupVars config
if [[ -f "/etc/pihole/setupVars.conf" ]]; then
setupVars="/etc/pihole/setupVars.conf"
fi
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
}
get_sys_stats() {
local ph_ver_raw
local cpu_raw
local ram_raw
local disk_raw
# Update every 12 refreshes (Def: every 60s)
count=$((count+1))
if [[ "$count" == "1" ]] || (( "$count" % 12 == 0 )); then
# Do not source setupVars if file does not exist
[[ -n "$setupVars" ]] && source "$setupVars"
mapfile -t ph_ver_raw < <(pihole -v -c 2> /dev/null | sed -n 's/^.* v/v/p')
if [[ -n "${ph_ver_raw[0]}" ]]; then
ph_core_ver="${ph_ver_raw[0]}"
ph_lte_ver="${ph_ver_raw[1]}"
ph_ftl_ver="${ph_ver_raw[2]}"
else
ph_core_ver="-1"
fi
sys_name=$(hostname)
[[ -n "$TEMPERATUREUNIT" ]] && temp_unit="$TEMPERATUREUNIT" || temp_unit="c"
# Get storage stats for partition mounted on /
read -r -a disk_raw <<< "$(df -B1 / 2> /dev/null | awk 'END{ print $3,$2,$5 }')"
disk_used="${disk_raw[0]}"
disk_total="${disk_raw[1]}"
disk_perc="${disk_raw[2]}"
net_gateway=$(route -n | awk '$4 == "UG" {print $2;exit}')
# Get DHCP stats, if feature is enabled
if [[ "$DHCP_ACTIVE" == "true" ]]; then
ph_dhcp_max=$(( ${DHCP_END##*.} - ${DHCP_START##*.} + 1 ))
fi
# Get DNS server count
dns_count="0"
[[ -n "${PIHOLE_DNS_1}" ]] && dns_count=$((dns_count+1))
[[ -n "${PIHOLE_DNS_2}" ]] && dns_count=$((dns_count+1))
[[ -n "${PIHOLE_DNS_3}" ]] && dns_count=$((dns_count+1))
[[ -n "${PIHOLE_DNS_4}" ]] && dns_count=$((dns_count+1))
[[ -n "${PIHOLE_DNS_5}" ]] && dns_count=$((dns_count+1))
[[ -n "${PIHOLE_DNS_6}" ]] && dns_count=$((dns_count+1))
[[ -n "${PIHOLE_DNS_7}" ]] && dns_count=$((dns_count+1))
[[ -n "${PIHOLE_DNS_8}" ]] && dns_count=$((dns_count+1))
[[ -n "${PIHOLE_DNS_9}" ]] && dns_count="$dns_count+"
fi
# Get screen size
read -r -a scr_size <<< "$(stty size 2>/dev/null || echo 24 80)"
scr_lines="${scr_size[0]}"
scr_cols="${scr_size[1]}"
# Determine Chronometer size behaviour
if [[ "$scr_cols" -ge 58 ]]; then
chrono_width="large"
elif [[ "$scr_cols" -gt 40 ]]; then
chrono_width="medium"
else
chrono_width="small"
fi
# Determine max length of divider string
scr_line_len=$(( scr_cols - 2 ))
[[ "$scr_line_len" -ge 58 ]] && scr_line_len="58"
scr_line_str=$(printf "%${scr_line_len}s")
scr_line_str="${scr_line_str// /—}"
sys_uptime=$(hrSecs "$(cut -d. -f1 /proc/uptime)")
sys_loadavg=$(cut -d " " -f1,2,3 /proc/loadavg)
# Get CPU usage, only counting processes over 1% as active
# shellcheck disable=SC2009
cpu_raw=$(ps -eo pcpu,rss --no-headers | grep -E -v " 0")
cpu_tasks=$(wc -l <<< "$cpu_raw")
cpu_taskact=$(sed -r "/(^ 0.)/d" <<< "$cpu_raw" | wc -l)
cpu_perc=$(awk '{sum+=$1} END {printf "%.0f\n", sum/'"$sys_cores"'}' <<< "$cpu_raw")
# Get CPU clock speed
if [[ -n "$scaling_freq_file" ]]; then
cpu_mhz=$(( $(< /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 ))
else
cpu_mhz=$(lscpu | awk -F ":" '/MHz/ {print $2;exit}')
cpu_mhz=$(printf "%.0f" "${cpu_mhz//[[:space:]]/}")
fi
# Determine whether to display CPU clock speed as MHz or GHz
if [[ -n "$cpu_mhz" ]]; then
[[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(printf "%.1f" $(calcFunc "$cpu_mhz"/1000)) GHz"
[[ "${cpu_freq}" == *".0"* ]] && cpu_freq="${cpu_freq/.0/}"
fi
# Determine colour for temperature
if [[ -n "$temp_file" ]]; then
if [[ "$temp_unit" == "C" ]]; then
cpu_temp=$(printf "%.0fc\\n" "$(calcFunc "$(< $temp_file) / 1000")")
case "${cpu_temp::-1}" in
-*|[0-9]|[1-3][0-9]) cpu_col="$COL_LIGHT_BLUE";;
4[0-9]) cpu_col="";;
5[0-9]) cpu_col="$COL_YELLOW";;
6[0-9]) cpu_col="$COL_LIGHT_RED";;
*) cpu_col="$COL_URG_RED";;
esac
# $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED
cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
elif [[ "$temp_unit" == "F" ]]; then
cpu_temp=$(printf "%.0ff\\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")")
case "${cpu_temp::-1}" in
-*|[0-9]|[0-9][0-9]) cpu_col="$COL_LIGHT_BLUE";;
1[0-1][0-9]) cpu_col="";;
1[2-3][0-9]) cpu_col="$COL_YELLOW";;
1[4-5][0-9]) cpu_col="$COL_LIGHT_RED";;
*) cpu_col="$COL_URG_RED";;
esac
cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
else
cpu_temp_str=$(printf " @ %.0fk\\n" "$(calcFunc "($(< $temp_file) / 1000) + 273.15")")
fi
else
cpu_temp_str=""
fi
read -r -a ram_raw <<< "$(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.0f %.0f %.0f", (total-free-buffers-cached)*100/total, (total-free-buffers-cached)*1024, total*1024}' /proc/meminfo)"
ram_perc="${ram_raw[0]}"
ram_used="${ram_raw[1]}"
ram_total="${ram_raw[2]}"
if [[ "$(pihole status web 2> /dev/null)" == "1" ]]; then
ph_status="${COL_LIGHT_GREEN}Active"
else
ph_status="${COL_LIGHT_RED}Offline"
fi
if [[ "$DHCP_ACTIVE" == "true" ]]; then
local ph_dhcp_range
ph_dhcp_range=$(seq -s "|" -f "${DHCP_START%.*}.%g" "${DHCP_START##*.}" "${DHCP_END##*.}")
# Count dynamic leases from available range, and not static leases
ph_dhcp_num=$(grep -cE "$ph_dhcp_range" "/etc/pihole/dhcp.leases")
ph_dhcp_percent=$(( ph_dhcp_num * 100 / ph_dhcp_max ))
fi
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
}
get_ftl_stats() {
local stats_raw
mapfile -t stats_raw < <(pihole-FTL "stats")
domains_being_blocked_raw="${stats_raw[0]#* }"
dns_queries_today_raw="${stats_raw[1]#* }"
ads_blocked_today_raw="${stats_raw[2]#* }"
ads_percentage_today_raw="${stats_raw[3]#* }"
queries_forwarded_raw="${stats_raw[5]#* }"
queries_cached_raw="${stats_raw[6]#* }"
# Only retrieve these stats when not called from jsonFunc
if [[ -z "$1" ]]; then
local top_ad_raw
local top_domain_raw
local top_client_raw
domains_being_blocked=$(printf "%.0f\\n" "${domains_being_blocked_raw}" 2> /dev/null)
dns_queries_today=$(printf "%.0f\\n" "${dns_queries_today_raw}")
ads_blocked_today=$(printf "%.0f\\n" "${ads_blocked_today_raw}")
ads_percentage_today=$(printf "%'.0f\\n" "${ads_percentage_today_raw}")
queries_cached_percentage=$(printf "%.0f\\n" "$(calcFunc "$queries_cached_raw * 100 / ( $queries_forwarded_raw + $queries_cached_raw )")")
recent_blocked=$(pihole-FTL recentBlocked)
read -r -a top_ad_raw <<< "$(pihole-FTL "top-ads (1)")"
read -r -a top_domain_raw <<< "$(pihole-FTL "top-domains (1)")"
read -r -a top_client_raw <<< "$(pihole-FTL "top-clients (1)")"
top_ad="${top_ad_raw[2]}"
top_domain="${top_domain_raw[2]}"
if [[ "${top_client_raw[3]}" ]]; then
top_client="${top_client_raw[3]}"
else
top_client="${top_client_raw[2]}"
fi
fi
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
}
get_strings() {
# Expand or contract strings depending on screen size
if [[ "$chrono_width" == "large" ]]; then
phc_str=" ${COL_DARK_GRAY}Core"
lte_str=" ${COL_DARK_GRAY}Web"
ftl_str=" ${COL_DARK_GRAY}FTL"
api_str="${COL_LIGHT_RED}API Offline"
function outputJSON(){
CalcQueriesToday
CalcblockedToday
CalcPercentBlockedToday
host_info="$sys_type"
sys_info="$sys_throttle"
sys_info2="Active: $cpu_taskact of $cpu_tasks tasks"
used_str="Used: "
leased_str="Leased: "
domains_being_blocked=$(printf "%'.0f" "$domains_being_blocked")
ads_blocked_today=$(printf "%'.0f" "$ads_blocked_today")
dns_queries_today=$(printf "%'.0f" "$dns_queries_today")
ph_info="Blocking: $domains_being_blocked sites"
total_str="Total: "
else
phc_str=" ${COL_DARK_GRAY}Core"
lte_str=" ${COL_DARK_GRAY}Web"
ftl_str=" ${COL_DARK_GRAY}FTL"
api_str="${COL_LIGHT_RED}API Down"
ph_info="$domains_being_blocked blocked"
fi
CalcBlockedDomains
[[ "$sys_cores" -ne 1 ]] && sys_cores_txt="${sys_cores}x "
cpu_info="$sys_cores_txt$cpu_freq$cpu_temp_str"
ram_info="$used_str$(hrBytes "$ram_used") of $(hrBytes "$ram_total")"
disk_info="$used_str$(hrBytes "$disk_used") of $(hrBytes "$disk_total")"
lan_info="Gateway: $net_gateway"
dhcp_info="$leased_str$ph_dhcp_num of $ph_dhcp_max"
ads_info="$total_str$ads_blocked_today of $dns_queries_today"
dns_info="$dns_count DNS servers"
[[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}"
printf '{"domains_being_blocked":"%s","dns_queries_today":"%s","ads_blocked_today":"%s","ads_percentage_today":"%s"}\n' "$blockedDomainsTotal" "$queriesToday" "$blockedToday" "$percentBlockedToday"
}
chronoFunc() {
get_init_stats
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;}'
for (( ; ; )); do
get_sys_stats
get_ftl_stats
get_strings
#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)
# Strip excess development version numbers
if [[ "$ph_core_ver" != "-1" ]]; then
phc_ver_str="$phc_str: ${ph_core_ver%-*}${COL_NC}"
lte_ver_str="$lte_str: ${ph_lte_ver%-*}${COL_NC}"
ftl_ver_str="$ftl_str: ${ph_ftl_ver%-*}${COL_NC}"
else
phc_ver_str="$phc_str: $api_str${COL_NC}"
fi
# Get refresh number
if [[ "$*" == *"-r"* ]]; then
num="$*"
num="${num/*-r /}"
num="${num/ */}"
num_str="Refresh set for every $num seconds"
else
num_str=""
fi
CalcQueriesToday
CalcblockedToday
CalcPercentBlockedToday
clear
CalcBlockedDomains
# Remove exit message heading on third refresh
if [[ "$count" -le 2 ]] && [[ "$*" != *"-e"* ]]; then
echo -e " ${COL_LIGHT_GREEN}Pi-hole Chronometer${COL_NC}
$num_str
${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC}
${COL_DARK_GRAY}$scr_line_str${COL_NC}"
else
echo -e "|¯¯¯(¯)_|¯|_ ___|¯|___$phc_ver_str
| ¯_/¯|_| ' \\/ _ \\ / -_)$lte_ver_str
|_| |_| |_||_\\___/_\\___|$ftl_ver_str
${COL_DARK_GRAY}$scr_line_str${COL_NC}"
fi
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%)"
printFunc " Hostname: " "$sys_name" "$host_info"
printFunc " Uptime: " "$sys_uptime" "$sys_info"
printFunc " Task Load: " "$sys_loadavg" "$sys_info2"
printFunc " CPU usage: " "$cpu_perc%" "$cpu_info"
printFunc " RAM usage: " "$ram_perc%" "$ram_info"
printFunc " HDD usage: " "$disk_perc" "$disk_info"
if [[ "$scr_lines" -gt 17 ]] && [[ "$chrono_width" != "small" ]]; then
printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}" "$lan_info"
fi
if [[ "$DHCP_ACTIVE" == "true" ]]; then
printFunc "DHCP usage: " "$ph_dhcp_percent%" "$dhcp_info"
fi
printFunc " Pi-hole: " "$ph_status" "$ph_info"
printFunc " Ads Today: " "$ads_percentage_today%" "$ads_info"
printFunc "Local Qrys: " "$queries_cached_percentage%" "$dns_info"
printFunc " Blocked: " "$recent_blocked"
printFunc "Top Advert: " "$top_ad"
# Provide more stats on screens with more lines
if [[ "$scr_lines" -eq 17 ]]; then
if [[ "$DHCP_ACTIVE" == "true" ]]; then
printFunc "Top Domain: " "$top_domain" "last"
else
print_client="true"
fi
else
print_client="true"
fi
if [[ -n "$print_client" ]]; then
printFunc "Top Domain: " "$top_domain"
printFunc "Top Client: " "$top_client" "last"
fi
# Handle exit/refresh options
if [[ "$*" == *"-e"* ]]; then
exit 0
else
if [[ "$*" == *"-r"* ]]; then
sleep "$num"
else
sleep 5
fi
fi
done
sleep 5
done
}
jsonFunc() {
get_ftl_stats "json"
echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}"
}
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"
helpFunc() {
if [[ "$1" == "?" ]]; then
echo "Unknown option. Please view 'pihole -c --help' for more information"
else
echo "Usage: pihole -c [options]
Example: 'pihole -c -j'
Calculates stats and displays to an LCD
Options:
-j, --json Output stats as JSON formatted string
-r, --refresh Set update frequency (in seconds)
-e, --exit Output stats and exit witout refreshing
-h, --help Display this help text"
fi
exit 0
exit 1
}
if [[ $# = 0 ]]; then
chronoFunc
normalChrono
fi
for var in "$@"; do
for var in "$@"
do
case "$var" in
"-j" | "--json" ) jsonFunc;;
"-h" | "--help" ) helpFunc;;
"-r" | "--refresh" ) chronoFunc "$@";;
"-e" | "--exit" ) chronoFunc "$@";;
* ) helpFunc "?";;
"-j" | "--json" ) outputJSON;;
"-h" | "--help" ) displayHelp;;
* ) exit 1;;
esac
done

View File

@@ -1,261 +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.
#
# Whitelist and blacklist domains
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
# Globals
basename=pihole
piholeDir=/etc/${basename}
whitelist=${piholeDir}/whitelist.txt
blacklist=${piholeDir}/blacklist.txt
readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
reload=false
addmode=true
verbose=true
domList=()
listMain=""
listAlt=""
colfile="/opt/pihole/COL_TABLE"
source ${colfile}
helpFunc() {
if [[ "${listMain}" == "${whitelist}" ]]; then
param="w"
type="white"
elif [[ "${listMain}" == "${wildcardlist}" ]]; then
param="wild"
type="wildcard black"
else
param="b"
type="black"
fi
echo "Usage: pihole -${param} [options] <domain> <domain2 ...>
Example: 'pihole -${param} site.com', or 'pihole -${param} site1.com site2.com'
${type^}list one or more domains
Options:
-d, --delmode Remove domain(s) from the ${type}list
-nr, --noreload Update ${type}list without refreshing dnsmasq
-q, --quiet Make output less verbose
-h, --help Show this help dialog
-l, --list Display all your ${type}listed domains
--nuke Removes all entries in a list"
exit 0
}
EscapeRegexp() {
# This way we may safely insert an arbitrary
# string in our regular expressions
# Also remove leading "." if present
echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g"
}
HandleOther() {
# Convert to lowercase
domain="${1,,}"
# Check validity of domain
if [[ "${#domain}" -le 253 ]]; then
validDomain=$(grep -P "^((-|_)*[a-z\d]((-|_)*[a-z\d])*(-|_)*)(\.(-|_)*([a-z\d]((-|_)*[a-z\d])*))*$" <<< "${domain}") # Valid chars check
validDomain=$(grep -P "^[^\.]{1,63}(\.[^\.]{1,63})*$" <<< "${validDomain}") # Length of each label
fi
if [[ -n "${validDomain}" ]]; then
domList=("${domList[@]}" ${validDomain})
else
echo -e " ${CROSS} ${domain} is not a valid argument or domain name!"
fi
}
PoplistFile() {
# Check whitelist file exists, and if not, create it
if [[ ! -f ${whitelist} ]]; then
touch ${whitelist}
fi
for dom in "${domList[@]}"; do
# Logic: If addmode then add to desired list and remove from the other; if delmode then remove from desired list but do not add to the other
if ${addmode}; then
AddDomain "${dom}" "${listMain}"
RemoveDomain "${dom}" "${listAlt}"
if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then
RemoveDomain "${dom}" "${wildcardlist}"
fi
else
RemoveDomain "${dom}" "${listMain}"
fi
done
}
AddDomain() {
list="$2"
domain=$(EscapeRegexp "$1")
[[ "${list}" == "${whitelist}" ]] && listname="whitelist"
[[ "${list}" == "${blacklist}" ]] && listname="blacklist"
[[ "${list}" == "${wildcardlist}" ]] && listname="wildcard blacklist"
if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
[[ "${list}" == "${whitelist}" && -z "${type}" ]] && type="--whitelist-only"
[[ "${list}" == "${blacklist}" && -z "${type}" ]] && type="--blacklist-only"
bool=true
# Is the domain in the list we want to add it to?
grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
if [[ "${bool}" == false ]]; then
# Domain not found in the whitelist file, add it!
if [[ "${verbose}" == true ]]; then
echo -e " ${INFO} Adding $1 to $listname..."
fi
reload=true
# Add it to the list we want to add it to
echo "$1" >> "${list}"
else
if [[ "${verbose}" == true ]]; then
echo -e " ${INFO} ${1} already exists in ${listname}, no need to add!"
fi
fi
elif [[ "${list}" == "${wildcardlist}" ]]; then
source "${piholeDir}/setupVars.conf"
# Remove the /* from the end of the IP addresses
IPV4_ADDRESS=${IPV4_ADDRESS%/*}
IPV6_ADDRESS=${IPV6_ADDRESS%/*}
[[ -z "${type}" ]] && type="--wildcard-only"
bool=true
# Is the domain in the list?
grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
if [[ "${bool}" == false ]]; then
if [[ "${verbose}" == true ]]; then
echo -e " ${INFO} Adding $1 to wildcard blacklist..."
fi
reload="restart"
echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}"
if [[ "${#IPV6_ADDRESS}" > 0 ]]; then
echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}"
fi
else
if [[ "${verbose}" == true ]]; then
echo -e " ${INFO} ${1} already exists in wildcard blacklist, no need to add!"
fi
fi
fi
}
RemoveDomain() {
list="$2"
domain=$(EscapeRegexp "$1")
[[ "${list}" == "${whitelist}" ]] && listname="whitelist"
[[ "${list}" == "${blacklist}" ]] && listname="blacklist"
[[ "${list}" == "${wildcardlist}" ]] && listname="wildcard blacklist"
if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
bool=true
[[ "${list}" == "${whitelist}" && -z "${type}" ]] && type="--whitelist-only"
[[ "${list}" == "${blacklist}" && -z "${type}" ]] && type="--blacklist-only"
# Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa
grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
if [[ "${bool}" == true ]]; then
# Remove it from the other one
echo -e " ${INFO} Removing $1 from $listname..."
# /I flag: search case-insensitive
sed -i "/${domain}/Id" "${list}"
reload=true
else
if [[ "${verbose}" == true ]]; then
echo -e " ${INFO} ${1} does not exist in ${listname}, no need to remove!"
fi
fi
elif [[ "${list}" == "${wildcardlist}" ]]; then
[[ -z "${type}" ]] && type="--wildcard-only"
bool=true
# Is it in the list?
grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
if [[ "${bool}" == true ]]; then
# Remove it from the other one
echo -e " ${INFO} Removing $1 from $listname..."
# /I flag: search case-insensitive
sed -i "/address=\/${domain}/Id" "${list}"
reload=true
else
if [[ "${verbose}" == true ]]; then
echo -e " ${INFO} ${1} does not exist in ${listname}, no need to remove!"
fi
fi
fi
}
# Update Gravity
Reload() {
echo ""
pihole -g --skip-download "${type:-}"
}
Displaylist() {
if [[ -f ${listMain} ]]; then
if [[ "${listMain}" == "${whitelist}" ]]; then
string="gravity resistant domains"
else
string="domains caught in the sinkhole"
fi
verbose=false
echo -e "Displaying $string:\n"
count=1
while IFS= read -r RD; do
echo " ${count}: ${RD}"
count=$((count+1))
done < "${listMain}"
else
echo -e " ${COL_LIGHT_RED}${listMain} does not exist!${COL_NC}"
fi
exit 0;
}
NukeList() {
if [[ -f "${listMain}" ]]; then
# Back up original list
cp "${listMain}" "${listMain}.bck~"
# Empty out file
echo "" > "${listMain}"
fi
}
for var in "$@"; do
case "${var}" in
"-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";;
"-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";;
"-wild" | "wildcard" ) listMain="${wildcardlist}";;
"-nr"| "--noreload" ) reload=false;;
"-d" | "--delmode" ) addmode=false;;
"-q" | "--quiet" ) verbose=false;;
"-h" | "--help" ) helpFunc;;
"-l" | "--list" ) Displaylist;;
"--nuke" ) NukeList;;
* ) HandleOther "${var}";;
esac
done
shift
if [[ $# = 0 ]]; then
helpFunc
fi
PoplistFile
if [[ "${reload}" != false ]]; then
# Ensure that "restart" is used for Wildcard updates
Reload "${reload}"
fi

View File

@@ -1,359 +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"
PH_TEST="true"
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
# setupVars set in basic-install.sh
source "${setupVars}"
update="false"
coltable="/opt/pihole/COL_TABLE"
source ${coltable}
check_download_exists() {
status=$(curl --head --silent "https://ftl.pi-hole.net/${1}" | head -n 1)
if grep -q "404" <<< "$status"; then
return 1
else
return 0
fi
}
FTLinstall() {
# Download and install FTL binary
local binary
binary="${1}"
local path
path="${2}"
local str
str="Installing FTL"
echo -ne " ${INFO} ${str}..."
if curl -sSL --fail "https://ftl.pi-hole.net/${path}" -o "/tmp/${binary}"; then
# Get sha1 of the binary we just downloaded for verification.
curl -sSL --fail "https://ftl.pi-hole.net/${path}.sha1" -o "/tmp/${binary}.sha1"
# Check if we just downloaded text, or a binary file.
cd /tmp || return 1
if sha1sum --status --quiet -c "${binary}".sha1; then
echo -n "transferred... "
stop_service pihole-FTL &> /dev/null
install -T -m 0755 "/tmp/${binary}" "/usr/bin/pihole-FTL"
rm "/tmp/${binary}" "/tmp/${binary}.sha1"
start_service pihole-FTL &> /dev/null
echo -e "${OVER} ${TICK} ${str}"
return 0
else
echo -e "${OVER} ${CROSS} ${str}"
echo -e " ${COL_LIGHT_RED}Error: Download of binary from ftl.pi-hole.net failed${COL_NC}"
return 1
fi
else
echo -e "${OVER} ${CROSS} ${str}"
echo -e " ${COL_LIGHT_RED}Error: URL not found${COL_NC}"
fi
}
get_binary_name() {
local machine
machine=$(uname -m)
local str
str="Detecting architecture"
echo -ne " ${INFO} ${str}..."
if [[ "${machine}" == "arm"* || "${machine}" == *"aarch"* ]]; then
# ARM
local rev
rev=$(uname -m | sed "s/[^0-9]//g;")
local lib
lib=$(ldd /bin/ls | grep -E '^\s*/lib' | awk '{ print $1 }')
if [[ "${lib}" == "/lib/ld-linux-aarch64.so.1" ]]; then
echo -e "${OVER} ${TICK} Detected ARM-aarch64 architecture"
binary="pihole-FTL-aarch64-linux-gnu"
elif [[ "${lib}" == "/lib/ld-linux-armhf.so.3" ]]; then
if [[ "$rev" -gt "6" ]]; then
echo -e "${OVER} ${TICK} Detected ARM-hf architecture (armv7+)"
binary="pihole-FTL-arm-linux-gnueabihf"
else
echo -e "${OVER} ${TICK} Detected ARM-hf architecture (armv6 or lower) Using ARM binary"
binary="pihole-FTL-arm-linux-gnueabi"
fi
else
echo -e "${OVER} ${TICK} Detected ARM architecture"
binary="pihole-FTL-arm-linux-gnueabi"
fi
elif [[ "${machine}" == "ppc" ]]; then
# PowerPC
echo -e "${OVER} ${TICK} Detected PowerPC architecture"
binary="pihole-FTL-powerpc-linux-gnu"
elif [[ "${machine}" == "x86_64" ]]; then
# 64bit
echo -e "${OVER} ${TICK} Detected x86_64 architecture"
binary="pihole-FTL-linux-x86_64"
else
# Something else - we try to use 32bit executable and warn the user
if [[ ! "${machine}" == "i686" ]]; then
echo -e "${OVER} ${CROSS} ${str}...
${COL_LIGHT_RED}Not able to detect architecture (unknown: ${machine}), trying 32bit executable
Contact support if you experience issues (e.g: FTL not running)${COL_NC}"
else
echo -e "${OVER} ${TICK} Detected 32bit (i686) architecture"
fi
binary="pihole-FTL-linux-x86_32"
fi
}
fully_fetch_repo() {
# Add upstream branches to shallow clone
local directory="${1}"
cd "${directory}" || return 1
if is_repo "${directory}"; then
git remote set-branches origin '*' || return 1
git fetch --quiet || return 1
else
return 1
fi
return 0
}
get_available_branches() {
# Return available branches
local directory
directory="${1}"
local output
cd "${directory}" || return 1
# Get reachable remote branches, but store STDERR as STDOUT variable
output=$( { git remote show origin | grep 'tracked' | sed 's/tracked//;s/ //g'; } 2>&1 )
echo "$output"
return
}
fetch_checkout_pull_branch() {
# Check out specified branch
local directory
directory="${1}"
local branch
branch="${2}"
# Set the reference for the requested branch, fetch, check it put and pull it
cd "${directory}" || return 1
git remote set-branches origin "${branch}" || return 1
git stash --all --quiet &> /dev/null || true
git clean --quiet --force -d || true
git fetch --quiet || return 1
checkout_pull_branch "${directory}" "${branch}" || return 1
}
checkout_pull_branch() {
# Check out specified branch
local directory
directory="${1}"
local branch
branch="${2}"
local oldbranch
cd "${directory}" || return 1
oldbranch="$(git symbolic-ref HEAD)"
str="Switching to branch: '${branch}' from '${oldbranch}'"
echo -ne " ${INFO} $str"
git checkout "${branch}" --quiet || return 1
echo -e "${OVER} ${TICK} $str"
if [[ "$(git diff "${oldbranch}" | grep -c "^")" -gt "0" ]]; then
update="true"
fi
git_pull=$(git pull || return 1)
if [[ "$git_pull" == *"up-to-date"* ]]; then
echo -e " ${INFO} ${git_pull}"
else
echo -e "$git_pull\\n"
fi
return 0
}
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_LIGHT_RED}This feature is NOT supported unless a Pi-hole developer explicitly asks!${COL_NC}"
read -r -p " Have you read and understood this? [y/N] " response
case "${response}" in
[yY][eE][sS]|[yY])
echo ""
return 0
;;
*)
echo -e "\\n ${INFO} Branch change has been cancelled"
return 1
;;
esac
}
checkout() {
local corebranches
local webbranches
# Avoid globbing
set -f
# This is unlikely
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
echo -e " ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!
Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
exit 1;
fi
if [[ "${INSTALL_WEB}" == "true" ]]; then
if ! is_repo "${webInterfaceDir}" ; then
echo -e " ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!
Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
exit 1;
fi
fi
if [[ -z "${1}" ]]; then
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}
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 \"dev\" detected - checking out development / devel branches..."
echo ""
echo -e " ${INFO} Pi-hole Core"
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core developement branch"; exit 1; }
if [[ "${INSTALL_WEB}" == "true" ]]; then
echo ""
echo -e " ${INFO} Web interface"
fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; }
fi
#echo -e " ${TICK} Pi-hole Core"
get_binary_name
local path
path="development/${binary}"
FTLinstall "${binary}" "${path}"
elif [[ "${1}" == "master" ]] ; then
# Shortcut to check out master branches
echo -e " ${INFO} Shortcut \"master\" 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; }
if [[ ${INSTALL_WEB} == "true" ]]; then
echo -e " ${INFO} Web interface"
fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; }
fi
#echo -e " ${TICK} Web Interface"
get_binary_name
local path
path="master/${binary}"
FTLinstall "${binary}" "${path}"
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
corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}"))
if [[ "${corebranches[*]}" == *"master"* ]]; then
echo -e "${OVER} ${TICK} $str
${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 \"${2}\" 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" ]] && [[ "${INSTALL_WEB}" == "true" ]] ; then
str="Fetching branches from ${webInterfaceGitUrl}"
echo -ne " ${INFO} $str"
if ! fully_fetch_repo "${webInterfaceDir}" ; then
echo -e "${OVER} ${CROSS} $str"
exit 1
fi
webbranches=($(get_available_branches "${webInterfaceDir}"))
if [[ "${webbranches[*]}" == *"master"* ]]; then
echo -e "${OVER} ${TICK} $str
${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 \"${2}\" 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}"
elif [[ "${1}" == "ftl" ]] ; then
get_binary_name
local path
path="${2}/${binary}"
if check_download_exists "$path"; then
echo " ${TICK} Branch ${2} exists"
FTLinstall "${binary}" "${path}"
else
echo " ${CROSS} Requested branch \"${2}\" is not available"
ftlbranches=( $(git ls-remote https://github.com/pi-hole/ftl | grep 'heads' | sed 's/refs\/heads\///;s/ //g' | awk '{print $2}') )
echo -e " ${INFO} Available branches for FTL are:"
for e in "${ftlbranches[@]}"; do echo " - $e"; done
exit 1
fi
else
echo -e " ${INFO} Requested option \"${1}\" is not available"
exit 1
fi
# Force updating everything
if [[ ( ! "${1}" == "web" && ! "${1}" == "ftl" ) && "${update}" == "true" ]]; 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_LIGHT_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,48 +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.
# 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.
colfile="/opt/pihole/COL_TABLE"
source ${colfile}
if [[ "$@" != *"quiet"* ]]; then
echo -ne " ${INFO} Flushing /var/log/pihole.log ..."
fi
if [[ "$@" == *"once"* ]]; then
# Nightly logrotation
if command -v /usr/sbin/logrotate >/dev/null; then
# Logrotate once
/usr/sbin/logrotate --force /etc/pihole/logrotate
else
# Copy pihole.log over to pihole.log.1
# and empty out pihole.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)
cp /var/log/pihole.log /var/log/pihole.log.1
echo " " > /var/log/pihole.log
fi
else
# Manual flushing
if command -v /usr/sbin/logrotate >/dev/null; then
# Logrotate twice to move all data out of sight of FTL
/usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3
/usr/sbin/logrotate --force /etc/pihole/logrotate
else
# Flush both pihole.log and pihole.log.1 (if existing)
echo " " > /var/log/pihole.log
if [ -f /var/log/pihole.log.1 ]; then
echo " " > /var/log/pihole.log.1
fi
fi
fi
if [[ "$@" != *"quiet"* ]]; then
echo -e "${OVER} ${TICK} Flushed /var/log/pihole.log"
fi
echo -n "::: Flushing /var/log/pihole.log ..."
truncate -s 0 /var/log/pihole.log
echo "... done!"

View File

@@ -1,42 +1,57 @@
#!/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 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)
#
# 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.
############ 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
if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then
SYSTEMD=1
elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then
SYSTEMD=0
else
echo "Unrecognised init system"
return 1
fi
}
# Borrowed from adafruit-pitft-helper:
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L274-L285
autoLoginPiToConsole() {
if [ -e /etc/init.d/lightdm ]; then
if [ ${SYSTEMD} -eq 1 ]; then
systemctl set-default multi-user.target
ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
else
update-rc.d lightdm disable 2
sed /etc/inittab -i -e "s/1:2345:respawn:\/sbin\/getty --noclear 38400 tty1/1:2345:respawn:\/bin\/login -f pi tty1 <\/dev\/tty1 >\/dev\/tty1 2>&1/"
fi
fi
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 ###########
@@ -51,23 +66,23 @@ echo /usr/local/bin/chronometer.sh >> /home/pi/.bashrc
# Set up the LCD screen based on Adafruits instuctions:
# https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/easy-install
curl -SLs https://apt.adafruit.com/add-pin | bash
apt-get -y install raspberrypi-bootloader
apt-get -y install adafruit-pitft-helper
adafruit-pitft-helper -t 28r
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
mv /boot/cmdline.txt /boot/cmdline.orig
curl -o /boot/cmdline.txt https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/cmdline.txt
$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
mv /etc/default/console-setup /etc/default/console-setup.orig
curl -o /etc/default/console-setup https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/console-setup
$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
setupcon
$SUDO setupcon
reboot
$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

View File

@@ -1,228 +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/AdminLTE.git"
readonly ADMIN_INTERFACE_DIR="/var/www/html/admin"
readonly PI_HOLE_GIT_URL="https://github.com/pi-hole/pi-hole.git"
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
# shellcheck disable=SC2034
PH_TEST=true
# shellcheck disable=SC1090
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# shellcheck disable=SC1091
source "/opt/pihole/COL_TABLE"
# 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
GitCheckUpdateAvail() {
local directory="${1}"
curdir=$PWD
cd "${directory}" || return
# Fetch latest changes in this repo
git fetch --quiet origin
# @ alone is a shortcut for HEAD. Older versions of git
# need @{0}
LOCAL="$(git rev-parse "@{0}")"
# The suffix @{upstream} to a branchname
# (short form <branchname>@{u}) refers
# to the branch that the branch specified
# by branchname is set to build on top of#
# (configured with branch.<name>.remote and
# branch.<name>.merge). A missing branchname
# defaults to the current one.
REMOTE="$(git rev-parse "@{upstream}")"
if [[ "${#LOCAL}" == 0 ]]; then
echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support
Additional debugging output:${COL_NC}"
git status
exit
fi
if [[ "${#REMOTE}" == 0 ]]; then
echo -e "\\n ${COL_LIGHT_RED}Error: Remote revision could not be obtained, please contact Pi-hole Support
Additional debugging output:${COL_NC}"
git status
exit
fi
# Change back to original directory
cd "${curdir}" || exit
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
}
FTLcheckUpdate() {
local FTLversion
FTLversion=$(/usr/bin/pihole-FTL tag)
local FTLlatesttag
FTLlatesttag=$(curl -sI https://github.com/pi-hole/FTL/releases/latest | grep 'Location' | awk -F '/' '{print $NF}' | tr -d '\r\n')
if [[ "${FTLversion}" != "${FTLlatesttag}" ]]; then
return 0
else
return 1
fi
}
main() {
local pihole_version_current
local web_version_current
local basicError="\\n ${COL_LIGHT_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
# shellcheck disable=1090,2154
source "${setupVars}"
# This is unlikely
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!
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_LIGHT_GREEN}up to date${COL_NC}"
fi
if FTLcheckUpdate ; then
FTL_update=true
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
else
FTL_update=false
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
fi
# Logic: Don't update FTL when there is a core update available
# since the core update will run the installer which will itself
# re-install (i.e. update) FTL
if ${FTL_update} && ! ${core_update}; then
echo ""
echo -e " ${INFO} FTL out of date"
FTLdetect
echo ""
fi
if [[ "${INSTALL_WEB}" == true ]]; then
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
echo -e "\\n ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!
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_LIGHT_GREEN}up to date${COL_NC}"
fi
# Logic
# If Core up to date AND web up to date:
# Do nothing
# If Core up to date AND web NOT up to date:
# Pull web repo
# If Core NOT up to date AND web up to date:
# pull pihole repo, run install --unattended -- reconfigure
# if Core NOT up to date AND web NOT up to date:
# pull pihole repo run install --unattended
if ! ${core_update} && ! ${web_update} ; then
if ! ${FTL_update} ; then
echo ""
echo -e " ${TICK} Everything is up to date!"
exit 0
fi
elif ! ${core_update} && ${web_update} ; then
echo ""
echo -e " ${INFO} Pi-hole Web Admin files out of date"
getGitFiles "${ADMIN_INTERFACE_DIR}" "${ADMIN_INTERFACE_GIT_URL}"
elif ${core_update} && ! ${web_update} ; then
echo ""
echo -e " ${INFO} Pi-hole core files out of date"
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
echo -e "${basicError}" && exit 1
elif ${core_update} && ${web_update} ; then
echo ""
echo -e " ${INFO} Updating Pi-hole core and web admin files"
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --unattended || \
echo -e "${basicError}" && exit 1
else
echo -e " ${COL_LIGHT_RED}Update script has malfunctioned, please contact Pi-hole Support${COL_NC}"
exit 1
fi
else # Web Admin not installed, so only verify if core is up to date
if ! ${core_update}; then
if ! ${FTL_update} ; then
echo ""
echo -e " ${INFO} Everything is up to date!"
exit 0
fi
else
echo ""
echo -e " ${INFO} Pi-hole Core files out of date"
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
echo -e "${basicError}" && exit 1
fi
fi
if [[ "${web_update}" == true ]]; then
web_version_current="$(/usr/local/bin/pihole version --admin --current)"
echo ""
echo -e " ${INFO} Web Admin version is now at ${web_version_current/* v/v}
${INFO} If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'"
fi
if [[ "${core_update}" == true ]]; then
pihole_version_current="$(/usr/local/bin/pihole version --pihole --current)"
echo ""
echo -e " ${INFO} Pi-hole version is now at ${pihole_version_current/* v/v}
${INFO} If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'"
fi
if [[ "${FTL_update}" == true ]]; then
FTL_version_current="$(/usr/bin/pihole-FTL tag)"
echo -e "\\n ${INFO} FTL version is now at ${FTL_version_current/* v/v}"
start_service pihole-FTL
enable_service pihole-FTL
fi
echo ""
exit 0
}
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,66 +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.
# Credit: https://stackoverflow.com/a/46324904
function json_extract() {
local key=$1
local json=$2
local string_regex='"([^"\]|\\.)*"'
local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
local value_regex="${string_regex}|${number_regex}|true|false|null"
local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"
if [[ ${json} =~ ${pair_regex} ]]; then
echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
else
return 1
fi
}
function get_local_branch() {
# Return active branch
cd "${1}" 2> /dev/null || return 1
git rev-parse --abbrev-ref HEAD || return 1
}
function get_local_version() {
# Return active branch
cd "${1}" 2> /dev/null || return 1
git describe --long --dirty --tags || return 1
}
if [[ "$2" == "remote" ]]; then
if [[ "$3" == "reboot" ]]; then
sleep 30
fi
GITHUB_CORE_VERSION="$(json_extract tag_name "$(curl -q 'https://api.github.com/repos/pi-hole/pi-hole/releases/latest' 2> /dev/null)")"
GITHUB_WEB_VERSION="$(json_extract tag_name "$(curl -q 'https://api.github.com/repos/pi-hole/AdminLTE/releases/latest' 2> /dev/null)")"
GITHUB_FTL_VERSION="$(json_extract tag_name "$(curl -q 'https://api.github.com/repos/pi-hole/FTL/releases/latest' 2> /dev/null)")"
echo "${GITHUB_CORE_VERSION} ${GITHUB_WEB_VERSION} ${GITHUB_FTL_VERSION}" > "/etc/pihole/GitHubVersions"
else
CORE_BRANCH="$(get_local_branch /etc/.pihole)"
WEB_BRANCH="$(get_local_branch /var/www/html/admin)"
FTL_BRANCH="$(pihole-FTL branch)"
echo "${CORE_BRANCH} ${WEB_BRANCH} ${FTL_BRANCH}" > "/etc/pihole/localbranches"
CORE_VERSION="$(get_local_version /etc/.pihole)"
WEB_VERSION="$(get_local_version /var/www/html/admin)"
FTL_VERSION="$(pihole-FTL version)"
echo "${CORE_VERSION} ${WEB_VERSION} ${FTL_VERSION}" > "/etc/pihole/localversions"
fi

View File

@@ -1,168 +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.
#
# Show version numbers
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
# Variables
DEFAULT="-1"
COREGITDIR="/etc/.pihole/"
WEBGITDIR="/var/www/html/admin/"
getLocalVersion() {
# FTL requires a different method
if [[ "$1" == "FTL" ]]; then
pihole-FTL version
return 0
fi
# Get the tagged version of the local repository
local directory="${1}"
local version
cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
version=$(git describe --tags --always || echo "$DEFAULT")
if [[ "${version}" =~ ^v ]]; then
echo "${version}"
elif [[ "${version}" == "${DEFAULT}" ]]; then
echo "ERROR"
return 1
else
echo "Untagged"
fi
return 0
}
getLocalHash() {
# Local FTL hash does not exist on filesystem
if [[ "$1" == "FTL" ]]; then
echo "N/A"
return 0
fi
# Get the short hash of the local repository
local directory="${1}"
local hash
cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
hash=$(git rev-parse --short HEAD || echo "$DEFAULT")
if [[ "${hash}" == "${DEFAULT}" ]]; then
echo "ERROR"
return 1
else
echo "${hash}"
fi
return 0
}
getRemoteHash(){
# Remote FTL hash is not applicable
if [[ "$1" == "FTL" ]]; then
echo "N/A"
return 0
fi
local daemon="${1}"
local branch="${2}"
hash=$(git ls-remote --heads "https://github.com/pi-hole/${daemon}" | \
awk -v bra="$branch" '$0~bra {print substr($0,0,8);exit}')
if [[ -n "$hash" ]]; then
echo "$hash"
else
echo "ERROR"
return 1
fi
return 0
}
getRemoteVersion(){
# Get the version from the remote origin
local daemon="${1}"
local version
version=$(curl --silent --fail "https://api.github.com/repos/pi-hole/${daemon}/releases/latest" | \
awk -F: '$1 ~/tag_name/ { print $2 }' | \
tr -cd '[[:alnum:]]._-')
if [[ "${version}" =~ ^v ]]; then
echo "${version}"
else
echo "ERROR"
return 1
fi
return 0
}
versionOutput() {
[[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
[[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
[[ "$1" == "FTL" ]] && GITDIR="FTL"
[[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $GITDIR)
[[ "$2" == "-l" ]] || [[ "$2" == "--latest" ]] || [[ -z "$2" ]] && latest=$(getRemoteVersion "$1")
if [[ "$2" == "-h" ]] || [[ "$2" == "--hash" ]]; then
[[ "$3" == "-c" ]] || [[ "$3" == "--current" ]] || [[ -z "$3" ]] && curHash=$(getLocalHash "$GITDIR")
[[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)")
fi
if [[ -n "$current" ]] && [[ -n "$latest" ]]; then
output="${1^} version is $current (Latest: $latest)"
elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then
output="Current ${1^} version is $current"
elif [[ -z "$current" ]] && [[ -n "$latest" ]]; then
output="Latest ${1^} version is $latest"
elif [[ "$curHash" == "N/A" ]] || [[ "$latHash" == "N/A" ]]; then
output="${1^} hash is not applicable"
elif [[ -n "$curHash" ]] && [[ -n "$latHash" ]]; then
output="${1^} hash is $curHash (Latest: $latHash)"
elif [[ -n "$curHash" ]] && [[ -z "$latHash" ]]; then
output="Current ${1^} hash is $curHash"
elif [[ -z "$curHash" ]] && [[ -n "$latHash" ]]; then
output="Latest ${1^} hash is $latHash"
else
errorOutput
fi
[[ -n "$output" ]] && echo " $output"
}
errorOutput() {
echo " Invalid Option! Try 'pihole -v --help' for more information."
exit 1
}
defaultOutput() {
versionOutput "pi-hole" "$@"
versionOutput "AdminLTE" "$@"
versionOutput "FTL" "$@"
}
helpFunc() {
echo "Usage: pihole -v [repo | option] [option]
Example: 'pihole -v -p -l'
Show Pi-hole, Admin Console & FTL versions
Repositories:
-p, --pihole Only retrieve info regarding Pi-hole repository
-a, --admin Only retrieve info regarding AdminLTE repository
-f, --ftl Only retrieve info regarding FTL repository
Options:
-c, --current Return the current version
-l, --latest Return the latest version
--hash Return the Github hash from your local repositories
-h, --help Show this help dialog"
exit 0
}
case "${1}" in
"-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";;
"-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";;
"-f" | "--ftl" ) shift; versionOutput "FTL" "$@";;
"-h" | "--help" ) helpFunc;;
* ) defaultOutput "$@";;
esac

View File

@@ -1,525 +0,0 @@
#!/usr/bin/env bash
# shellcheck disable=SC1090
# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# Web interface settings
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
readonly setupVars="/etc/pihole/setupVars.conf"
readonly dnsmasqconfig="/etc/dnsmasq.d/01-pihole.conf"
readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf"
# 03 -> wildcards
readonly dhcpstaticconfig="/etc/dnsmasq.d/04-pihole-static-dhcp.conf"
coltable="/opt/pihole/COL_TABLE"
if [[ -f ${coltable} ]]; then
source ${coltable}
fi
helpFunc() {
echo "Usage: pihole -a [options]
Example: pihole -a -p password
Set options for the Admin Console
Options:
-p, password Set Admin Console password
-c, celsius Set Celsius as preferred temperature unit
-f, fahrenheit Set Fahrenheit as preferred temperature unit
-k, kelvin Set Kelvin as preferred temperature unit
-r, hostrecord Add a name to the DNS associated to an IPv4/IPv6 address
-e, email Set an administrative contact address for the Block Page
-h, --help Show this help dialog
-i, interface Specify dnsmasq's interface listening behavior
Add '-h' for more info on interface usage"
exit 0
}
add_setting() {
echo "${1}=${2}" >> "${setupVars}"
}
delete_setting() {
sed -i "/${1}/d" "${setupVars}"
}
change_setting() {
delete_setting "${1}"
add_setting "${1}" "${2}"
}
add_dnsmasq_setting() {
if [[ "${2}" != "" ]]; then
echo "${1}=${2}" >> "${dnsmasqconfig}"
else
echo "${1}" >> "${dnsmasqconfig}"
fi
}
delete_dnsmasq_setting() {
sed -i "/${1}/d" "${dnsmasqconfig}"
}
SetTemperatureUnit() {
change_setting "TEMPERATUREUNIT" "${unit}"
echo -e " ${TICK} Set temperature unit to ${unit}"
}
HashPassword() {
# Compute password hash twice to avoid rainbow table vulnerability
return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//')
return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//')
echo ${return}
}
SetWebPassword() {
if [ "${SUDO_USER}" == "www-data" ]; then
echo "Security measure: user www-data is not allowed to change webUI password!"
echo "Exiting"
exit 1
fi
if [ "${SUDO_USER}" == "lighttpd" ]; then
echo "Security measure: user lighttpd is not allowed to change webUI password!"
echo "Exiting"
exit 1
fi
if (( ${#args[2]} > 0 )) ; then
readonly PASSWORD="${args[2]}"
readonly CONFIRM="${PASSWORD}"
else
# Prevents a bug if the user presses Ctrl+C and it continues to hide the text typed.
# So we reset the terminal via stty if the user does press Ctrl+C
trap '{ echo -e "\nNo password will be set" ; stty sane ; exit 1; }' INT
read -s -p "Enter New Password (Blank for no password): " PASSWORD
echo ""
if [ "${PASSWORD}" == "" ]; then
change_setting "WEBPASSWORD" ""
echo -e " ${TICK} Password Removed"
exit 0
fi
read -s -p "Confirm Password: " CONFIRM
echo ""
fi
if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
hash=$(HashPassword "${PASSWORD}")
# Save hash to file
change_setting "WEBPASSWORD" "${hash}"
echo -e " ${TICK} New password set"
else
echo -e " ${CROSS} Passwords don't match. Your password has not been changed"
exit 1
fi
}
ProcessDNSSettings() {
source "${setupVars}"
delete_dnsmasq_setting "server"
COUNTER=1
while [[ 1 ]]; do
var=PIHOLE_DNS_${COUNTER}
if [ -z "${!var}" ]; then
break;
fi
add_dnsmasq_setting "server" "${!var}"
let COUNTER=COUNTER+1
done
delete_dnsmasq_setting "domain-needed"
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
add_dnsmasq_setting "domain-needed"
fi
delete_dnsmasq_setting "bogus-priv"
if [[ "${DNS_BOGUS_PRIV}" == true ]]; then
add_dnsmasq_setting "bogus-priv"
fi
delete_dnsmasq_setting "dnssec"
delete_dnsmasq_setting "trust-anchor="
if [[ "${DNSSEC}" == true ]]; then
echo "dnssec
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D
" >> "${dnsmasqconfig}"
fi
delete_dnsmasq_setting "host-record"
if [ ! -z "${HOSTRECORD}" ]; then
add_dnsmasq_setting "host-record" "${HOSTRECORD}"
fi
# Setup interface listening behavior of dnsmasq
delete_dnsmasq_setting "interface"
delete_dnsmasq_setting "local-service"
if [[ "${DNSMASQ_LISTENING}" == "all" ]]; then
# Listen on all interfaces, permit all origins
add_dnsmasq_setting "except-interface" "nonexisting"
elif [[ "${DNSMASQ_LISTENING}" == "local" ]]; then
# Listen only on all interfaces, but only local subnets
add_dnsmasq_setting "local-service"
else
# Listen only on one interface
add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
fi
}
SetDNSServers() {
# Save setting to file
delete_setting "PIHOLE_DNS"
IFS=',' read -r -a array <<< "${args[2]}"
for index in "${!array[@]}"
do
add_setting "PIHOLE_DNS_$((index+1))" "${array[index]}"
done
if [[ "${args[3]}" == "domain-needed" ]]; then
change_setting "DNS_FQDN_REQUIRED" "true"
else
change_setting "DNS_FQDN_REQUIRED" "false"
fi
if [[ "${args[4]}" == "bogus-priv" ]]; then
change_setting "DNS_BOGUS_PRIV" "true"
else
change_setting "DNS_BOGUS_PRIV" "false"
fi
if [[ "${args[5]}" == "dnssec" ]]; then
change_setting "DNSSEC" "true"
else
change_setting "DNSSEC" "false"
fi
ProcessDNSSettings
# Restart dnsmasq to load new configuration
RestartDNS
}
SetExcludeDomains() {
change_setting "API_EXCLUDE_DOMAINS" "${args[2]}"
}
SetExcludeClients() {
change_setting "API_EXCLUDE_CLIENTS" "${args[2]}"
}
Poweroff(){
nohup bash -c "sleep 5; poweroff" &> /dev/null </dev/null &
}
Reboot() {
nohup bash -c "sleep 5; reboot" &> /dev/null </dev/null &
}
RestartDNS() {
/usr/local/bin/pihole restartdns
}
SetQueryLogOptions() {
change_setting "API_QUERY_LOG_SHOW" "${args[2]}"
}
ProcessDHCPSettings() {
source "${setupVars}"
if [[ "${DHCP_ACTIVE}" == "true" ]]; then
interface=$(grep 'PIHOLE_INTERFACE=' /etc/pihole/setupVars.conf | sed "s/.*=//")
# Use eth0 as fallback interface
if [ -z ${interface} ]; then
interface="eth0"
fi
if [[ "${PIHOLE_DOMAIN}" == "" ]]; then
PIHOLE_DOMAIN="local"
change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}"
fi
if [[ "${DHCP_LEASETIME}" == "0" ]]; then
leasetime="infinite"
elif [[ "${DHCP_LEASETIME}" == "" ]]; then
leasetime="24"
change_setting "DHCP_LEASETIME" "${leasetime}"
elif [[ "${DHCP_LEASETIME}" == "24h" ]]; then
#Installation is affected by known bug, introduced in a previous version.
#This will automatically clean up setupVars.conf and remove the unnecessary "h"
leasetime="24"
change_setting "DHCP_LEASETIME" "${leasetime}"
else
leasetime="${DHCP_LEASETIME}h"
fi
# Write settings to file
echo "###############################################################################
# DHCP SERVER CONFIG FILE AUTOMATICALLY POPULATED BY PI-HOLE WEB INTERFACE. #
# ANY CHANGES MADE TO THIS FILE WILL BE LOST ON CHANGE #
###############################################################################
dhcp-authoritative
dhcp-range=${DHCP_START},${DHCP_END},${leasetime}
dhcp-option=option:router,${DHCP_ROUTER}
dhcp-leasefile=/etc/pihole/dhcp.leases
#quiet-dhcp
" > "${dhcpconfig}"
if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
fi
if [[ "${DHCP_IPv6}" == "true" ]]; then
echo "#quiet-dhcp6
#enable-ra
dhcp-option=option6:dns-server,[::]
dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,${leasetime}
ra-param=*,0,0
" >> "${dhcpconfig}"
fi
else
if [[ -f "${dhcpconfig}" ]]; then
rm "${dhcpconfig}" &> /dev/null
fi
fi
}
EnableDHCP() {
change_setting "DHCP_ACTIVE" "true"
change_setting "DHCP_START" "${args[2]}"
change_setting "DHCP_END" "${args[3]}"
change_setting "DHCP_ROUTER" "${args[4]}"
change_setting "DHCP_LEASETIME" "${args[5]}"
change_setting "PIHOLE_DOMAIN" "${args[6]}"
change_setting "DHCP_IPv6" "${args[7]}"
# Remove possible old setting from file
delete_dnsmasq_setting "dhcp-"
delete_dnsmasq_setting "quiet-dhcp"
ProcessDHCPSettings
RestartDNS
}
DisableDHCP() {
change_setting "DHCP_ACTIVE" "false"
# Remove possible old setting from file
delete_dnsmasq_setting "dhcp-"
delete_dnsmasq_setting "quiet-dhcp"
ProcessDHCPSettings
RestartDNS
}
SetWebUILayout() {
change_setting "WEBUIBOXEDLAYOUT" "${args[2]}"
}
CustomizeAdLists() {
list="/etc/pihole/adlists.list"
if [[ "${args[2]}" == "enable" ]]; then
sed -i "\\@${args[3]}@s/^#http/http/g" "${list}"
elif [[ "${args[2]}" == "disable" ]]; then
sed -i "\\@${args[3]}@s/^http/#http/g" "${list}"
elif [[ "${args[2]}" == "add" ]]; then
echo "${args[3]}" >> ${list}
elif [[ "${args[2]}" == "del" ]]; then
var=$(echo "${args[3]}" | sed 's/\//\\\//g')
sed -i "/${var}/Id" "${list}"
else
echo "Not permitted"
return 1
fi
}
SetPrivacyMode() {
if [[ "${args[2]}" == "true" ]]; then
change_setting "API_PRIVACY_MODE" "true"
else
change_setting "API_PRIVACY_MODE" "false"
fi
}
ResolutionSettings() {
typ="${args[2]}"
state="${args[3]}"
if [[ "${typ}" == "forward" ]]; then
change_setting "API_GET_UPSTREAM_DNS_HOSTNAME" "${state}"
elif [[ "${typ}" == "clients" ]]; then
change_setting "API_GET_CLIENT_HOSTNAME" "${state}"
fi
}
AddDHCPStaticAddress() {
mac="${args[2]}"
ip="${args[3]}"
host="${args[4]}"
if [[ "${ip}" == "noip" ]]; then
# Static host name
echo "dhcp-host=${mac},${host}" >> "${dhcpstaticconfig}"
elif [[ "${host}" == "nohost" ]]; then
# Static IP
echo "dhcp-host=${mac},${ip}" >> "${dhcpstaticconfig}"
else
# Full info given
echo "dhcp-host=${mac},${ip},${host}" >> "${dhcpstaticconfig}"
fi
}
RemoveDHCPStaticAddress() {
mac="${args[2]}"
sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}"
}
SetHostRecord() {
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
echo "Usage: pihole -a hostrecord <domain> [IPv4-address],[IPv6-address]
Example: 'pihole -a hostrecord home.domain.com 192.168.1.1,2001:db8:a0b:12f0::1'
Add a name to the DNS associated to an IPv4/IPv6 address
Options:
\"\" Empty: Remove host record
-h, --help Show this help dialog"
exit 0
fi
if [[ -n "${args[3]}" ]]; then
change_setting "HOSTRECORD" "${args[2]},${args[3]}"
echo -e " ${TICK} Setting host record for ${args[2]} to ${args[3]}"
else
change_setting "HOSTRECORD" ""
echo -e " ${TICK} Removing host record"
fi
ProcessDNSSettings
# Restart dnsmasq to load new configuration
RestartDNS
}
SetAdminEmail() {
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
echo "Usage: pihole -a email <address>
Example: 'pihole -a email admin@address.com'
Set an administrative contact address for the Block Page
Options:
\"\" Empty: Remove admin contact
-h, --help Show this help dialog"
exit 0
fi
if [[ -n "${args[2]}" ]]; then
change_setting "ADMIN_EMAIL" "${args[2]}"
echo -e " ${TICK} Setting admin contact to ${args[2]}"
else
change_setting "ADMIN_EMAIL" ""
echo -e " ${TICK} Removing admin contact"
fi
}
SetListeningMode() {
source "${setupVars}"
if [[ "$3" == "-h" ]] || [[ "$3" == "--help" ]]; then
echo "Usage: pihole -a -i [interface]
Example: 'pihole -a -i local'
Specify dnsmasq's network interface listening behavior
Interfaces:
local Listen on all interfaces, but only allow queries from
devices that are at most one hop away (local devices)
single Listen only on ${PIHOLE_INTERFACE} interface
all Listen on all interfaces, permit all origins"
exit 0
fi
if [[ "${args[2]}" == "all" ]]; then
echo -e " ${INFO} Listening on all interfaces, permiting all origins. Please use a firewall!"
change_setting "DNSMASQ_LISTENING" "all"
elif [[ "${args[2]}" == "local" ]]; then
echo -e " ${INFO} Listening on all interfaces, permiting origins from one hop away (LAN)"
change_setting "DNSMASQ_LISTENING" "local"
else
echo -e " ${INFO} Listening only on interface ${PIHOLE_INTERFACE}"
change_setting "DNSMASQ_LISTENING" "single"
fi
# Don't restart DNS server yet because other settings
# will be applied afterwards if "-web" is set
if [[ "${args[3]}" != "-web" ]]; then
ProcessDNSSettings
# Restart dnsmasq to load new configuration
RestartDNS
fi
}
Teleporter() {
local datetimestamp=$(date "+%Y-%m-%d_%H-%M-%S")
php /var/www/html/admin/scripts/pi-hole/php/teleporter.php > "pi-hole-teleporter_${datetimestamp}.zip"
}
audit()
{
echo "${args[2]}" >> /etc/pihole/auditlog.list
}
main() {
args=("$@")
case "${args[1]}" in
"-p" | "password" ) SetWebPassword;;
"-c" | "celsius" ) unit="C"; SetTemperatureUnit;;
"-f" | "fahrenheit" ) unit="F"; SetTemperatureUnit;;
"-k" | "kelvin" ) unit="K"; SetTemperatureUnit;;
"setdns" ) SetDNSServers;;
"setexcludedomains" ) SetExcludeDomains;;
"setexcludeclients" ) SetExcludeClients;;
"poweroff" ) Poweroff;;
"reboot" ) Reboot;;
"restartdns" ) RestartDNS;;
"setquerylog" ) SetQueryLogOptions;;
"enabledhcp" ) EnableDHCP;;
"disabledhcp" ) DisableDHCP;;
"layout" ) SetWebUILayout;;
"-h" | "--help" ) helpFunc;;
"privacymode" ) SetPrivacyMode;;
"resolve" ) ResolutionSettings;;
"addstaticdhcp" ) AddDHCPStaticAddress;;
"removestaticdhcp" ) RemoveDHCPStaticAddress;;
"-r" | "hostrecord" ) SetHostRecord "$3";;
"-e" | "email" ) SetAdminEmail "$3";;
"-i" | "interface" ) SetListeningMode "$@";;
"-t" | "teleporter" ) Teleporter;;
"adlist" ) CustomizeAdLists;;
"audit" ) audit;;
* ) helpFunc;;
esac
shift
if [[ $# = 0 ]]; then
helpFunc
fi
}

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,11 +1,12 @@
_pihole() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="admin blacklist chronometer debug disable enable flush help logging query reconfigure restartdns setupLCD status tail uninstall updateGravity updatePihole version whitelist checkout"
_pihole()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="whitelist blacklist debug flush updateDashboard updateGravity setupLCD chronometer uninstall help"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
}
complete -F _pihole pihole
complete -F _pihole pihole

View File

@@ -1,383 +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.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* Text Customisation Options ======> */
.title:before { content: "Website Blocked"; }
.altBtn:before { content: "Why am I here?"; }
.linkPH:before { content: "About Pi-hole"; }
.linkEmail:before { content: "Contact Admin"; }
#bpOutput.add:before { content: "Info"; }
#bpOutput.add:after { content: "The domain is being whitelisted..."; }
#bpOutput.error:before, .unhandled:before { content: "Error"; }
#bpOutput.unhandled:after { content: "An unhandled exception occured. This may happen when your browser is unable to load jQuery, or when the webserver is denying access to the Pi-hole API."; }
#bpOutput.success:before { content: "Success"; }
#bpOutput.success:after { content: "Website has been whitelisted! You may need to flush your DNS cache"; }
.recentwl:before { content: "This site has been whitelisted. Please flush your DNS cache and/or restart your browser."; }
.unknown:before { content: "This website is not found in any of Pi-hole's blacklists. The reason you have arrived here is unknown."; }
.cname:before { content: "This site is an alias for "; } /* <a href="http://cname.com">cname.com</a> */
.cname:after { content: ", which may be blocked by Pi-hole."; }
.blacklist:before { content: "Manually Blacklisted"; }
.wildcard:before { content: "Manually Blacklisted by Wildcard"; }
.noblock:before { content: "Not found on any Blacklist"; }
#bpBlock:before { content: "Access to the following website has been denied:"; }
#bpFlag:before { content: "This is primarily due to being flagged as:"; }
#bpHelpTxt:before { content: "If you have an ongoing use for this website, please "; }
#bpHelpTxt a:before, #bpHelpTxt span:before { content: "ask the administrator"; }
#bpHelpTxt:after{ content: " of the Pi-hole on this network to have it whitelisted"; }
#bpBack:before { content: "Back to safety"; }
#bpInfo:before { content: "Technical Info"; }
#bpFoundIn:before { content: "This site is found in "; }
#bpFoundIn span:after { content: " of "; }
#bpFoundIn:after { content: " lists:"; }
#bpWhitelist:before { content: "Whitelist"; }
footer span:before { content: "Page generated on "; }
/* Hide whitelisting form entirely */
/* #bpWLButtons { display: none; } */
/* Text Customisation Options <=============================== */
/* http://necolas.github.io/normalize.css ======> */
html { font-family: sans-serif; line-height: 1.15; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; }
body { margin: 0; }
article, aside, footer, header, nav, section { display: block; }
h1 { font-size: 2em; margin: 0.67em 0; }
figcaption, figure, main { display: block; }
figure { margin: 1em 40px; }
hr { box-sizing: content-box; height: 0; overflow: visible; }
pre { font-family: monospace, monospace; font-size: 1em; }
a { background-color: transparent; -webkit-text-decoration-skip: objects; }
a:active, a:hover { outline-width: 0; }
abbr[title] { border-bottom: none; text-decoration: underline; text-decoration: underline dotted; }
b, strong { font-weight: inherit; }
b, strong { font-weight: bolder; }
code, kbd, samp { font-family: monospace, monospace; font-size: 1em; }
dfn { font-style: italic; }
mark { background-color: #ff0; color: #000; }
small { font-size: 80%; }
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
sub { bottom: -0.25em; }
sup { top: -0.5em; }
audio, video { display: inline-block; }
audio:not([controls]) { display: none; height: 0; }
img { border-style: none; }
svg:not(:root) { overflow: hidden; }
button, input, optgroup, select, textarea { font-family: sans-serif; font-size: 100%; line-height: 1.15; margin: 0; }
button, input { overflow: visible; }
button, select { text-transform: none; }
button, html [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; }
button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; }
button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; }
fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }
legend { box-sizing: border-box; color: inherit; display: table; max-width: 100%; padding: 0; white-space: normal; }
progress { display: inline-block; vertical-align: baseline; }
textarea { overflow: auto; }
[type="checkbox"], [type="radio"] { box-sizing: border-box; padding: 0; }
[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; }
[type="search"] { -webkit-appearance: textfield; outline-offset: -2px; }
[type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
::-webkit-file-upload-button { -webkit-appearance: button; font: inherit; }
details, menu { display: block; }
summary { display: list-item; }
canvas { display: inline-block; }
template { display: none; }
[hidden] { display: none; }
/* Normalize.css <=============================== */
html { font-size: 62.5%; }
a { color: #3c8dbc; text-decoration: none; }
a:hover { color: #72afda; text-decoration: underline; }
b { color: rgb(68,68,68); }
p { margin: 0; }
label, .buttons a {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
label, .buttons *:not([disabled]) { cursor: pointer; }
/* Touch device dark tap highlight */
header h1 a, label, .buttons * { -webkit-tap-highlight-color: transparent; }
/* Webkit Focus Glow */
textarea, input, button { outline: none; }
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 400;
src: local("Source Sans Pro"), local("SourceSansPro-Regular"), url("/admin/style/vendor/SourceSansPro/SourceSansPro-Regular.ttf") format("truetype");
}
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 700;
src: local("Source Sans Pro Bold"), local("SourceSansPro-Bold"), url("/admin/style/vendor/SourceSansPro/SourceSansPro-Bold.ttf") format("truetype");
}
body {
background: #dbdbdb url("/admin/img/boxed-bg.jpg") repeat fixed;
color: #333;
font: 1.4rem "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 2.2rem;
}
/* User is greeted with a splash page when browsing to Pi-hole IP address */
#splashpage { background: #222; color: rgba(255,255,255,0.7); text-align: center; }
#splashpage img { margin: 5px; width: 256px; }
#splashpage b { color: inherit; }
#bpWrapper {
margin: 0 auto;
max-width: 1250px;
box-shadow: 0 0 8px rgba(0,0,0,0.5);
}
header {
background: #3c8dbc;
display: table;
position: relative;
width: 100%;
}
header h1, header h1 a, header .spc, header #bpAlt label {
display: table-cell;
color: #fff;
white-space: nowrap;
vertical-align: middle;
height: 50px; /* Must match #bpAbout top value */
}
h1 a {
background-color: rgba(0,0,0,0.1);
font-family: "Helvetica Neue", Helvetica, Arial ,sans-serif;
font-size: 2rem;
font-weight: normal;
min-width: 230px;
text-align: center;
}
h1 a:hover, header #bpAlt:hover { background-color: rgba(0,0,0,0.12); color: inherit; text-decoration: none; }
header .spc { width: 100%; }
header #bpAlt label {
background: url("/admin/img/logo.svg") no-repeat center left 15px;
background-size: 15px 23px;
padding: 0 15px;
text-indent: 30px;
}
[type=checkbox][id$="Toggle"] { display: none; }
[type=checkbox][id$="Toggle"]:checked ~ #bpAbout,
[type=checkbox][id$="Toggle"]:checked ~ #bpMoreInfo {
display: block; }
/* Click anywhere else on screen to hide #bpAbout */
#bpAboutToggle:checked {
display: block;
height: 300px; /* VH Fallback */
height: 100vh;
left: 0;
top: 0;
opacity: 0;
position: absolute;
width: 100%;
}
#bpAbout {
background: #3c8dbc;
border-bottom-left-radius: 5px;
border: 1px solid #FFF;
border-right-width: 0;
box-shadow: -1px 1px 1px rgba(0,0,0,0.12);
box-sizing: border-box;
display: none;
font-size: 1.7rem;
top: 50px;
position: absolute;
right: 0;
width: 280px;
z-index: 1;
}
.aboutPH {
box-sizing: border-box;
color: rgba(255,255,255,0.8);
display: block;
padding: 10px;
width: 100%;
text-align: center;
}
.aboutImg {
background: url("/admin/img/logo.svg") no-repeat center;
background-size: 90px 90px;
height: 90px;
margin: 0 auto;
padding: 2px;
width: 90px;
}
.aboutPH p { margin: 10px 0; }
.aboutPH small { display: block; font-size: 1.2rem; }
.aboutLink {
background: #fff;
border-top: 1px solid #ddd;
display: table;
font-size: 1.4rem;
text-align: center;
width: 100%;
}
.aboutLink a {
display: table-cell;
padding: 14px;
min-width: 50%;
}
main {
background: #ecf0f5;
font-size: 1.65rem;
padding: 10px;
}
#bpOutput {
background: #00c0ef;
border-radius: 3px;
border: 1px solid rgba(0,0,0,0.1);
color: #fff;
font-size: 1.4rem;
margin-bottom: 10px;
margin-top: 5px;
padding: 15px;
}
#bpOutput:before {
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='14' viewBox='0 0 7 14'%3E%3Cpath fill='%23fff' d='M6,11a1.371,1.371,0,0,1,1,1v1a1.371,1.371,0,0,1-1,1H1a1.371,1.371,0,0,1-1-1V12a1.371,1.371,0,0,1,1-1H2V8H1A1.371,1.371,0,0,1,0,7V6A1.371,1.371,0,0,1,1,5H4A1.371,1.371,0,0,1,5,6v5H6ZM3.5,0A1.5,1.5,0,1,1,2,1.5,1.5,1.5,0,0,1,3.5,0Z'/%3E%3C/svg%3E") no-repeat center left;
display: block;
font-size: 1.8rem;
text-indent: 15px;
}
#bpOutput.hidden { display: none; }
#bpOutput.success { background: #00a65a; }
#bpOutput.error { background: #dd4b39; }
.blockMsg, .flagMsg {
font: bold 1.8rem Consolas, Courier, monospace;
padding: 5px 10px 10px 10px;
text-indent: 15px;
}
#bpHelpTxt { padding-bottom: 10px; }
.buttons {
border-spacing: 5px 0;
display: table;
width: 100%;
}
.buttons * {
-moz-appearance: none;
-webkit-appearance: none;
border-radius: 3px;
border: 1px solid rgba(0,0,0,0.1);
box-sizing: content-box;
display: table-cell;
font-size: 1.65rem;
margin-right: 5px;
min-height: 20px;
padding: 6px 12px;
position: relative;
text-align: center;
vertical-align: top;
white-space: nowrap;
width: auto;
}
.buttons a:hover { text-decoration: none; }
/* Button hover dark overlay */
.buttons *:not(input):not([disabled]):hover {
background-image: linear-gradient(to bottom, rgba(0,0,0,0.1), rgba(0,0,0,0.1));
color: #FFF;
}
/* Button active shadow inset */
.buttons *:not([disabled]):not(input):active {
box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
}
/* Input border colour */
.buttons *:not([disabled]):hover, .buttons input:focus {
border-color: rgba(0,0,0,0.25);
}
#bpButtons * { width: 50%; color: #FFF; }
#bpBack { background-color: #00a65a; }
#bpInfo { background-color: #3c8dbc; }
#bpWhitelist { background-color: #dd4b39; }
#blockpage .buttons [type=password][disabled] { color: rgba(0,0,0,1); }
#blockpage .buttons [disabled] { color: rgba(0,0,0,0.55); background-color: #e3e3e3; }
#blockpage .buttons [type=password]:-ms-input-placeholder { color: rgba(51,51,51,0.8); }
input[type=password] { font-size: 1.5rem; }
@keyframes slidein { from { max-height: 0; opacity: 0; } to { max-height: 300px; opacity: 1; } }
#bpMoreToggle:checked ~ #bpMoreInfo { display: block; margin-top: 8px; animation: slidein 0.05s linear; }
#bpMoreInfo { display: none; margin-top: 10px; }
#bpQueryOutput {
font-size: 1.2rem;
line-height: 1.65rem;
margin: 5px 0 0 0;
overflow: auto;
padding: 0 5px;
-webkit-overflow-scrolling: touch;
}
#bpQueryOutput span { margin-right: 4px; }
#bpWLButtons { width: auto; margin-top: 10px; }
#bpWLButtons * { display: inline-block; }
#bpWLDomain { display: none; }
#bpWLPassword { width: 160px; }
#bpWhitelist { color: #fff; }
footer {
background: #fff;
border-top: 1px solid #d2d6de;
color: #444;
font: 1.2rem Consolas, Courier, monospace;
padding: 8px;
}
/* Responsive Content */
@media only screen and (max-width: 500px) {
h1 a { font-size: 1.8rem; min-width: 170px; }
footer span:before { content: "Generated "; }
footer span { display: block; }
}
@media only screen and (min-width: 1251px) {
#bpWrapper, footer { border-radius: 0 0 5px 5px; }
#bpAbout { border-right-width: 1px; }
}

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

View File

@@ -1,346 +0,0 @@
<?php
/* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
// Sanitise HTTP_HOST output
$serverName = htmlspecialchars($_SERVER["HTTP_HOST"]);
if (!is_file("/etc/pihole/setupVars.conf"))
die("[ERROR] File not found: <code>/etc/pihole/setupVars.conf</code>");
// Get values from setupVars.conf
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
$svPasswd = !empty($setupVars["WEBPASSWORD"]);
$svEmail = (!empty($setupVars["ADMIN_EMAIL"]) && filter_var($setupVars["ADMIN_EMAIL"], FILTER_VALIDATE_EMAIL)) ? $setupVars["ADMIN_EMAIL"] : "";
unset($setupVars);
// Set landing page location, found within /var/www/html/
$landPage = "../landing.php";
// Define array for hostnames to be accepted as self address for splash page
$authorizedHosts = [];
if (!empty($_SERVER["FQDN"])) {
// If setenv.add-environment = ("fqdn" => "true") is configured in lighttpd,
// append $serverName to $authorizedHosts
array_push($authorizedHosts, $serverName);
} else if (!empty($_SERVER["VIRTUAL_HOST"])) {
// Append virtual hostname to $authorizedHosts
array_push($authorizedHosts, $_SERVER["VIRTUAL_HOST"]);
}
// Set which extension types render as Block Page (Including "" for index.ext)
$validExtTypes = array("asp", "htm", "html", "php", "rss", "xml", "");
// Get extension of current URL
$currentUrlExt = pathinfo($_SERVER["REQUEST_URI"], PATHINFO_EXTENSION);
// Check if this is served over HTTP or HTTPS
if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") {
$proto = "https";
} else {
$proto = "http";
}
// Set mobile friendly viewport
$viewPort = '<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>';
// Set response header
function setHeader($type = "x") {
header("X-Pi-hole: A black hole for Internet advertisements.");
if (isset($type) && $type === "js") header("Content-Type: application/javascript");
}
// Determine block page type
if ($serverName === "pi.hole") {
// Redirect to Web Interface
exit(header("Location: /admin"));
} elseif (filter_var($serverName, FILTER_VALIDATE_IP) || in_array($serverName, $authorizedHosts)) {
// Set Splash Page output
$splashPage = "
<html><head>
$viewPort
<link rel='stylesheet' href='/pihole/blockingpage.css' type='text/css'/>
</head><body id='splashpage'><img src='/admin/img/logo.svg'/><br/>Pi-<b>hole</b>: Your black hole for Internet advertisements</body></html>
";
// Set splash/landing page based off presence of $landPage
$renderPage = is_file(getcwd()."/$landPage") ? include $landPage : "$splashPage";
// Unset variables so as to not be included in $landPage
unset($serverName, $svPasswd, $svEmail, $authorizedHosts, $validExtTypes, $currentUrlExt, $viewPort);
// Render splash/landing page when directly browsing via IP or authorised hostname
exit($renderPage);
} elseif ($currentUrlExt === "js") {
// Serve Pi-hole Javascript for blocked domains requesting JS
exit(setHeader("js").'var x = "Pi-hole: A black hole for Internet advertisements."');
} elseif (strpos($_SERVER["REQUEST_URI"], "?") !== FALSE && isset($_SERVER["HTTP_REFERER"])) {
// Serve blank image upon receiving REQUEST_URI w/ query string & HTTP_REFERRER
// e.g: An iframe of a blocked domain
exit(setHeader().'<html>
<head><script>window.close();</script></head>
<body><img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="></body>
</html>');
} elseif (!in_array($currentUrlExt, $validExtTypes) || substr_count($_SERVER["REQUEST_URI"], "?")) {
// Serve SVG upon receiving non $validExtTypes URL extension or query string
// e.g: Not an iframe of a blocked domain, such as when browsing to a file/query directly
// QoL addition: Allow the SVG to be clicked on in order to quickly show the full Block Page
$blockImg = '<a href="/"><svg xmlns="http://www.w3.org/2000/svg" width="110" height="16"><defs><style>a {text-decoration: none;} circle {stroke: rgba(152,2,2,0.5); fill: none; stroke-width: 2;} rect {fill: rgba(152,2,2,0.5);} text {opacity: 0.3; font: 11px Arial;}</style></defs><circle cx="8" cy="8" r="7"/><rect x="10.3" y="-6" width="2" height="12" transform="rotate(45)"/><text x="19.3" y="12">Blocked by Pi-hole</text></svg></a>';
exit(setHeader()."<html>
<head>$viewPort</head>
<body>$blockImg</body>
</html>");
}
/* Start processing Block Page from here */
// Determine placeholder text based off $svPasswd presence
$wlPlaceHolder = empty($svPasswd) ? "No admin password set" : "Javascript disabled";
// Define admin email address text based off $svEmail presence
$bpAskAdmin = !empty($svEmail) ? '<a href="mailto:'.$svEmail.'?subject=Site Blocked: '.$serverName.'"></a>' : "<span/>";
// Determine if at least one block list has been generated
if (empty(glob("/etc/pihole/list.0.*.domains")))
die("[ERROR] There are no domain lists generated lists within <code>/etc/pihole/</code>! Please update gravity by running <code>pihole -g</code>, or repair Pi-hole using <code>pihole -r</code>.");
// Set location of adlists file
if (is_file("/etc/pihole/adlists.list")) {
$adLists = "/etc/pihole/adlists.list";
} elseif (is_file("/etc/pihole/adlists.default")) {
$adLists = "/etc/pihole/adlists.default";
} else {
die("[ERROR] File not found: <code>/etc/pihole/adlists.list</code>");
}
// Get all URLs starting with "http" or "www" from adlists and re-index array numerically
$adlistsUrls = array_values(preg_grep("/(^http)|(^www)/i", file($adLists, FILE_IGNORE_NEW_LINES)));
if (empty($adlistsUrls))
die("[ERROR]: There are no adlist URL's found within <code>$adLists</code>");
// Get total number of blocklists (Including Whitelist, Blacklist & Wildcard lists)
$adlistsCount = count($adlistsUrls) + 3;
// Set query timeout
ini_set("default_socket_timeout", 3);
// Logic for querying blocklists
function queryAds($serverName) {
// Determine the time it takes while querying adlists
$preQueryTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
$queryAds = file("http://127.0.0.1/admin/scripts/pi-hole/php/queryads.php?domain=$serverName&bp", FILE_IGNORE_NEW_LINES);
$queryAds = array_values(array_filter(preg_replace("/data:\s+/", "", $queryAds)));
$queryTime = sprintf("%.0f", (microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]) - $preQueryTime);
// Exception Handling
try {
// Define Exceptions
if (strpos($queryAds[0], "No exact results") !== FALSE) {
// Return "none" into $queryAds array
return array("0" => "none");
} else if ($queryTime >= ini_get("default_socket_timeout")) {
// Connection Timeout
throw new Exception ("Connection timeout (".ini_get("default_socket_timeout")."s)");
} elseif (!strpos($queryAds[0], ".") !== false) {
// Unknown $queryAds output
throw new Exception ("Unhandled error message (<code>$queryAds[0]</code>)");
}
return $queryAds;
} catch (Exception $e) {
// Return exception as array
return array("0" => "error", "1" => $e->getMessage());
}
}
// Get results of queryads.php exact search
$queryAds = queryAds($serverName);
// Pass error through to Block Page
if ($queryAds[0] === "error")
die("[ERROR]: Unable to parse results from <i>queryads.php</i>: <code>".$queryAds[1]."</code>");
// Count total number of matching blocklists
$featuredTotal = count($queryAds);
// Place results into key => value array
$queryResults = null;
foreach ($queryAds as $str) {
$value = explode(" ", $str);
@$queryResults[$value[0]] .= "$value[1]";
}
// Determine if domain has been blacklisted, whitelisted, wildcarded or CNAME blocked
if (strpos($queryAds[0], "blacklist") !== FALSE) {
$notableFlagClass = "blacklist";
$adlistsUrls = array("π" => substr($queryAds[0], 2));
} elseif (strpos($queryAds[0], "whitelist") !== FALSE) {
$notableFlagClass = "noblock";
$adlistsUrls = array("π" => substr($queryAds[0], 2));
$wlInfo = "recentwl";
} elseif (strpos($queryAds[0], "wildcard") !== FALSE) {
$notableFlagClass = "wildcard";
$adlistsUrls = array("π" => substr($queryAds[0], 2));
} elseif ($queryAds[0] === "none") {
$featuredTotal = "0";
$notableFlagClass = "noblock";
// QoL addition: Determine appropriate info message if CNAME exists
// Suggests to the user that $serverName has a CNAME (alias) that may be blocked
$dnsRecord = dns_get_record("$serverName")[0];
if (array_key_exists("target", $dnsRecord)) {
$wlInfo = $dnsRecord['target'];
} else {
$wlInfo = "unknown";
}
}
// Set #bpOutput notification
$wlOutputClass = (isset($wlInfo) && $wlInfo === "recentwl") ? $wlInfo : "hidden";
$wlOutput = (isset($wlInfo) && $wlInfo !== "recentwl") ? "<a href='http://$wlInfo'>$wlInfo</a>" : "";
// Get Pi-hole Core version
$phVersion = exec("cd /etc/.pihole/ && git describe --long --tags");
// Print $execTime on development branches
// Testing for - is marginally faster than "git rev-parse --abbrev-ref HEAD"
if (explode("-", $phVersion)[1] != "0")
$execTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
// Please Note: Text is added via CSS to allow an admin to provide a localised
// language without the need to edit this file
setHeader();
?>
<!DOCTYPE html>
<!-- Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL. -->
<html>
<head>
<meta charset="UTF-8">
<?=$viewPort ?>
<meta name="robots" content="noindex,nofollow"/>
<meta http-equiv="x-dns-prefetch-control" content="off">
<link rel="shortcut icon" href="<?=$proto ?>://pi.hole/admin/img/favicon.png" type="image/x-icon"/>
<link rel="stylesheet" href="<?=$proto ?>://pi.hole/pihole/blockingpage.css" type="text/css"/>
<title>● <?=$serverName ?></title>
<script src="<?=$proto ?>://pi.hole/admin/scripts/vendor/jquery.min.js"></script>
<script>
window.onload = function () {
<?php
// Remove href fallback from "Back to safety" button
if ($featuredTotal > 0) echo '$("#bpBack").removeAttr("href");';
// Enable whitelisting if $svPasswd is present & JS is available
if (!empty($svPasswd) && $featuredTotal > 0) {
echo '$("#bpWLPassword, #bpWhitelist").prop("disabled", false);';
echo '$("#bpWLPassword").attr("placeholder", "Password");';
}
?>
}
</script>
</head>
<body id="blockpage"><div id="bpWrapper">
<header>
<h1 id="bpTitle">
<a class="title" href="/"><?php //Website Blocked ?></a>
</h1>
<div class="spc"></div>
<input id="bpAboutToggle" type="checkbox"/>
<div id="bpAbout">
<div class="aboutPH">
<div class="aboutImg"/></div>
<p>Open Source Ad Blocker
<small>Designed for Raspberry Pi</small>
</p>
</div>
<div class="aboutLink">
<a class="linkPH" href="https://github.com/pi-hole/pi-hole/wiki/What-is-Pi-hole%3F-A-simple-explanation"><?php //About PH ?></a>
<?php if (!empty($svEmail)) echo '<a class="linkEmail" href="mailto:'.$svEmail.'"></a>'; ?>
</div>
</div>
<div id="bpAlt">
<label class="altBtn" for="bpAboutToggle"><?php //Why am I here? ?></label>
</div>
</header>
<main>
<div id="bpOutput" class="<?=$wlOutputClass ?>"><?=$wlOutput ?></div>
<div id="bpBlock">
<p class="blockMsg"><?=$serverName ?></p>
</div>
<?php if(isset($notableFlagClass)) { ?>
<div id="bpFlag">
<p class="flagMsg <?=$notableFlagClass ?>"></p>
</div>
<?php } ?>
<div id="bpHelpTxt"><?=$bpAskAdmin ?></div>
<div id="bpButtons" class="buttons">
<a id="bpBack" onclick="javascript:history.back()" href="about:home"></a>
<?php if ($featuredTotal > 0) echo '<label id="bpInfo" for="bpMoreToggle"></label>'; ?>
</div>
<input id="bpMoreToggle" type="checkbox">
<div id="bpMoreInfo">
<span id="bpFoundIn"><span><?=$featuredTotal ?></span><?=$adlistsCount ?></span>
<pre id='bpQueryOutput'><?php if ($featuredTotal > 0) foreach ($queryResults as $num => $value) { echo "<span>[$num]:</span>$adlistsUrls[$num]\n"; } ?></pre>
<form id="bpWLButtons" class="buttons">
<input id="bpWLDomain" type="text" value="<?=$serverName ?>" disabled/>
<input id="bpWLPassword" type="password" placeholder="<?=$wlPlaceHolder ?>" disabled/><button id="bpWhitelist" type="button" disabled></button>
</form>
</div>
</main>
<footer><span><?=date("l g:i A, F dS"); ?>.</span> Pi-hole <?=$phVersion ?> (<?=gethostname()."/".$_SERVER["SERVER_ADDR"]; if (isset($execTime)) printf("/%.2fs", $execTime); ?>)</footer>
</div>
<script>
function add() {
$("#bpOutput").removeClass("hidden error exception");
$("#bpOutput").addClass("add");
var domain = "<?=$serverName ?>";
var pw = $("#bpWLPassword");
if(domain.length === 0) {
return;
}
$.ajax({
url: "/admin/scripts/pi-hole/php/add.php",
method: "post",
data: {"domain":domain, "list":"white", "pw":pw.val()},
success: function(response) {
if(response.indexOf("Pi-hole blocking") !== -1) {
setTimeout(function(){window.location.reload(1);}, 10000);
$("#bpOutput").removeClass("add");
$("#bpOutput").addClass("success");
} else {
$("#bpOutput").removeClass("add");
$("#bpOutput").addClass("error");
$("#bpOutput").html(""+response+"");
}
},
error: function(jqXHR, exception) {
$("#bpOutput").removeClass("add");
$("#bpOutput").addClass("exception");
}
});
}
<?php if ($featuredTotal > 0) { ?>
$(document).keypress(function(e) {
if(e.which === 13 && $("#bpWLPassword").is(":focus")) {
add();
}
});
$("#bpWhitelist").on("click", function() {
add();
});
<?php } ?>
</script>
</body></html>

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

View File

@@ -1,75 +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.
#
# Lighttpd config for Pi-hole
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
###############################################################################
# FILE AUTOMATICALLY OVERWRITTEN BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
# #
# CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE: #
# /etc/lighttpd/external.conf #
###############################################################################
server.modules = (
"mod_access",
"mod_accesslog",
"mod_auth",
"mod_expire",
"mod_compress",
"mod_redirect",
"mod_setenv",
"mod_rewrite"
)
server.document-root = "/var/www/html"
server.error-handler-404 = "pihole/index.php"
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
server.errorlog = "/var/log/lighttpd/error.log"
server.pid-file = "/var/run/lighttpd.pid"
server.username = "www-data"
server.groupname = "www-data"
server.port = 80
accesslog.filename = "/var/log/lighttpd/access.log"
accesslog.format = "%{%s}t|%V|%r|%s|%b"
index-file.names = ( "index.php", "index.html", "index.lighttpd.html" )
url.access-deny = ( "~", ".inc", ".md", ".yml", ".ini" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
compress.cache-dir = "/var/cache/lighttpd/compress/"
compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" )
# 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"
# Prevent Lighttpd from enabling Let's Encrypt SSL for every blocked domain
#include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
include_shell "find /etc/lighttpd/conf-enabled -name '*.conf' -a ! -name 'letsencrypt.conf' -printf 'include \"%p\"\n' 2>/dev/null"
# If the URL starts with /admin, it is the Web interface
$HTTP["url"] =~ "^/admin/" {
# Create a response header for debugging using curl -I
setenv.add-response-header = (
"X-Pi-hole" => "The Pi-hole Web interface is working!",
"X-Frame-Options" => "DENY"
)
$HTTP["url"] =~ ".ttf$" {
# Allow Block Page access to local fonts
setenv.add-response-header = ( "Access-Control-Allow-Origin" => "*" )
}
}
# Block . files from being served, such as .git, .github, .gitignore
$HTTP["url"] =~ "^/admin/\.(.*)" {
url.access-deny = ("")
}
# Add user chosen options held in external file
include_shell "cat external.conf 2>/dev/null"

View File

@@ -1,93 +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.
#
# lighttpd config for Pi-hole
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
###############################################################################
# FILE AUTOMATICALLY OVERWRITTEN BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
# #
# CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE: #
# /etc/lighttpd/external.conf #
###############################################################################
server.modules = (
"mod_access",
"mod_auth",
"mod_fastcgi",
"mod_accesslog",
"mod_expire",
"mod_compress",
"mod_redirect",
"mod_setenv",
"mod_rewrite"
)
server.document-root = "/var/www/html"
server.error-handler-404 = "pihole/index.php"
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
server.errorlog = "/var/log/lighttpd/error.log"
server.pid-file = "/var/run/lighttpd.pid"
server.username = "lighttpd"
server.groupname = "lighttpd"
server.port = 80
accesslog.filename = "/var/log/lighttpd/access.log"
accesslog.format = "%{%s}t|%V|%r|%s|%b"
index-file.names = ( "index.php", "index.html", "index.lighttpd.html" )
url.access-deny = ( "~", ".inc", ".md", ".yml", ".ini" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
compress.cache-dir = "/var/cache/lighttpd/compress/"
compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" )
mimetype.assign = ( ".png" => "image/png",
".jpg" => "image/jpeg",
".jpeg" => "image/jpeg",
".html" => "text/html",
".css" => "text/css; charset=utf-8",
".js" => "application/javascript",
".json" => "application/json",
".txt" => "text/plain",
".svg" => "image/svg+xml" )
# default listening port for IPv6 falls back to the IPv4 port
#include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
#include_shell "/usr/share/lighttpd/create-mime.assign.pl"
#include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
fastcgi.server = ( ".php" =>
( "localhost" =>
(
"socket" => "/tmp/php-fastcgi.socket",
"bin-path" => "/usr/bin/php-cgi"
)
)
)
# If the URL starts with /admin, it is the Web interface
$HTTP["url"] =~ "^/admin/" {
# Create a response header for debugging using curl -I
setenv.add-response-header = (
"X-Pi-hole" => "The Pi-hole Web interface is working!",
"X-Frame-Options" => "DENY"
)
$HTTP["url"] =~ ".ttf$" {
# Allow Block Page access to local fonts
setenv.add-response-header = ( "Access-Control-Allow-Origin" => "*" )
}
}
# Block . files from being served, such as .git, .github, .gitignore
$HTTP["url"] =~ "^/admin/\.(.*)" {
url.access-deny = ("")
}
# Add user chosen options held in external file
include_shell "cat external.conf 2>/dev/null"

View File

@@ -1,21 +0,0 @@
/var/log/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
}

View File

@@ -1,80 +0,0 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: pihole-FTL
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# 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
FTLUSER=pihole
PIDFILE=/var/run/pihole-FTL.pid
get_pid() {
pidof "pihole-FTL"
}
is_running() {
ps "$(get_pid)" > /dev/null 2>&1
}
# Start the service
start() {
if is_running; then
echo "pihole-FTL is already running"
else
touch /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole.log
chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /etc/pihole
chmod 0644 /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole.log
su -s /bin/sh -c "/usr/bin/pihole-FTL" "$FTLUSER"
echo
fi
}
# Stop the service
stop() {
if is_running; then
kill "$(get_pid)"
for i in {1..5}; do
if ! is_running; then
break
fi
echo -n "."
sleep 1
done
echo
if is_running; then
echo "Not stopped; may still be shutting down or shutdown may have failed, killing now"
kill -9 "$(get_pid)"
exit 1
else
echo "Stopped"
fi
else
echo "Not running"
fi
echo
}
### main logic ###
case "$1" in
stop)
stop
;;
status)
status pihole-FTL
;;
start|restart|reload|condrestart)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|restart|reload|status}"
exit 1
esac
exit 0

View File

@@ -1,37 +1,30 @@
# 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
# 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 softare
# is updated or re-installed. Please make any changes to the appropriate crontab
# or other cron file snippets.
# 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: Update the ad sources once a week on Sunday at a random time in the
# early morning. Download any updates from the adlists
59 1 * * 7 root PATH="$PATH:/usr/local/bin/" pihole updateGravity
# 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 Pi-hole! Uncomment to enable auto update
#30 2 * * 7 root PATH="$PATH:/usr/local/bin/" pihole 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: 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/local/bin/" pihole flush once quiet
# 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
@reboot root /usr/sbin/logrotate /etc/pihole/logrotate
# 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: Grab local version and branch every 10 minutes
*/10 * * * * root PATH="$PATH:/usr/local/bin/" pihole updatechecker local
# Pi-hole: Grab remote version every 24 hours
59 17 * * * root PATH="$PATH:/usr/local/bin/" pihole updatechecker remote
@reboot root PATH="$PATH:/usr/local/bin/" pihole updatechecker remote reboot
# 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

View File

@@ -1,9 +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.
#
# Allows the WebUI to use Pi-hole commands
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
#

File diff suppressed because it is too large Load Diff

View File

@@ -1,223 +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.
source "/opt/pihole/COL_TABLE"
while true; do
read -rp " ${QST} Are you sure you would like to remove ${COL_WHITE}Pi-hole${COL_NC}? [y/N] " yn
case ${yn} in
[Yy]* ) break;;
[Nn]* ) echo -e "\n ${COL_LIGHT_GREEN}Uninstall has been cancelled${COL_NC}"; exit 0;;
* ) echo -e "\n ${COL_LIGHT_GREEN}Uninstall has been cancelled${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
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 -e " ${CROSS} ${str}
Script called with non-root privileges
The Pi-hole requires elevated privleges to uninstall"
exit 1
fi
else
echo "::: Please install sudo or run this as root."
exit 1
fi
fi
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
PH_TEST="true"
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# setupVars set in basic-install.sh
source "${setupVars}"
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"
}
# distro_check() sourced from basic-install.sh
distro_check
# Install packages used by the Pi-hole
if [[ "${INSTALL_WEB}" == true ]]; then
# Install the Web dependencies
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}" "${PIHOLE_WEB_DEPS[@]}")
# Otherwise,
else
# just install the Core dependencies
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}")
fi
# Compatability
if [ -x "$(command -v rpm)" ]; then
# Fedora Family
PKG_REMOVE="${PKG_MANAGER} remove -y"
package_check() {
rpm -qa | grep ^$1- > /dev/null
}
package_cleanup() {
${SUDO} ${PKG_MANAGER} -y autoremove
}
elif [ -x "$(command -v apt-get)" ]; then
# Debian Family
PKG_REMOVE="${PKG_MANAGER} -y remove --purge"
package_check() {
dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -c "ok installed"
}
package_cleanup() {
${SUDO} ${PKG_MANAGER} -y autoremove
${SUDO} ${PKG_MANAGER} -y autoclean
}
else
echo -e " ${CROSS} OS distribution not supported"
exit 1
fi
removeAndPurge() {
function removeAndPurge {
# Purge dependencies
echo ""
for i in "${DEPS[@]}"; do
package_check ${i} > /dev/null
if [[ "$?" -eq 0 ]]; then
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 " ${QST} Do you wish to remove ${COL_WHITE}${i}${COL_NC} from your system? [Y/N] " yn
case ${yn} in
[Yy]* )
echo -ne " ${INFO} Removing ${i}...";
${SUDO} ${PKG_REMOVE} "${i}" &> /dev/null;
echo -e "${OVER} ${INFO} Removed ${i}";
break;;
[Nn]* ) echo -e " ${INFO} Skipped ${i}"; break;;
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
echo -e " ${INFO} Package ${i} not installed"
printf ":::\tPackage %s not installed... Not removing.\n" "$i"
fi
done
# Remove dnsmasq config files
${SUDO} rm -f /etc/dnsmasq.conf /etc/dnsmasq.conf.orig /etc/dnsmasq.d/01-pihole.conf &> /dev/null
echo -e " ${TICK} Removing dnsmasq config files"
# 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
# Take care of any additional package cleaning
echo -ne " ${INFO} Removing & cleaning remaining dependencies..."
package_cleanup &> /dev/null
echo -e "${OVER} ${TICK} Removed & cleaned up remaining dependencies"
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";
# Call removeNoPurge to remove Pi-hole specific files
# Call removeNoPurge to remove PiHole specific files
removeNoPurge
}
removeNoPurge() {
# Only web directories/files that are created by Pi-hole should be removed
echo -ne " ${INFO} Removing Web Interface..."
${SUDO} rm -rf /var/www/html/admin &> /dev/null
${SUDO} rm -rf /var/www/html/pihole &> /dev/null
${SUDO} rm -f /var/www/html/index.lighttpd.orig &> /dev/null
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
# 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
$SUDO rm -rf /var/www/html &> /dev/null
fi
fi
echo -e "${OVER} ${TICK} Removed Web Interface"
# Attempt to preserve backwards compatibility with older versions
# to guarantee no additional changes were made to /etc/crontab after
# the installation of pihole, /etc/crontab.pihole should be permanently
# 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"
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
# 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"
echo "::: Removing cron.d/pihole..."
$SUDO rm /etc/cron.d/pihole &> /dev/null
fi
package_check lighttpd > /dev/null
if [[ $? -eq 1 ]]; then
${SUDO} rm -rf /etc/lighttpd/ &> /dev/null
echo -e " ${TICK} Removed lighttpd"
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
$SUDO mv /etc/lighttpd/lighttpd.conf.orig /etc/lighttpd/lighttpd.conf
fi
fi
${SUDO} rm -f /etc/dnsmasq.d/adList.conf &> /dev/null
${SUDO} rm -f /etc/dnsmasq.d/01-pihole.conf &> /dev/null
${SUDO} rm -rf /var/log/*pihole* &> /dev/null
${SUDO} rm -rf /etc/pihole/ &> /dev/null
${SUDO} rm -rf /etc/.pihole/ &> /dev/null
${SUDO} rm -rf /opt/pihole/ &> /dev/null
${SUDO} rm -f /usr/local/bin/pihole &> /dev/null
${SUDO} rm -f /etc/bash_completion.d/pihole &> /dev/null
${SUDO} rm -f /etc/sudoers.d/pihole &> /dev/null
echo -e " ${TICK} Removed config files"
# Remove FTL
if command -v pihole-FTL &> /dev/null; then
echo -ne " ${INFO} Removing pihole-FTL..."
if [[ -x "$(command -v systemctl)" ]]; then
systemctl stop pihole-FTL
else
service pihole-FTL stop
fi
${SUDO} rm -f /etc/init.d/pihole-FTL
${SUDO} rm -f /usr/bin/pihole-FTL
echo -e "${OVER} ${TICK} Removed pihole-FTL"
fi
# If the pihole user exists, then remove
if id "pihole" &> /dev/null; then
${SUDO} userdel -r pihole 2> /dev/null
if [[ "$?" -eq 0 ]]; then
echo -e " ${TICK} Removed 'pihole' user"
else
echo -e " ${CROSS} Unable to remove 'pihole' user"
fi
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_WHITE}curl -sSL https://install.pi-hole.net | bash${COL_NC}
${COL_LIGHT_RED}Please reset the DNS on your router/clients to restore internet connectivity
${COL_LIGHT_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 ###########
if command -v vcgencmd &> /dev/null; then
echo -e " ${INFO} All dependencies are safe to remove on Raspbian"
else
echo -e " ${INFO} Be sure to confirm if any dependencies should not be removed"
fi
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
echo -e " ${INFO} ${COL_YELLOW}The following dependencies may have been added by the Pi-hole install:"
echo -n " "
for i in "${DEPS[@]}"; do
echo -n "${i} "
done
echo "${COL_NC}"
read -rp " ${QST} Do you wish to go through each dependency for removal? (Choosing No will leave all dependencies installed) [Y/n] " yn
case ${yn} in
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;;
* ) removeAndPurge; break;;
esac
done

View File

@@ -1 +0,0 @@
py.test -v -f test/

View File

@@ -1,673 +1,340 @@
#!/usr/bin/env bash
# shellcheck disable=SC1090
# Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
#
# Usage: "pihole -g"
# (c) 2015 by Jacob Salmela
# Network-wide ad blocking via your Raspberry Pi
# http://pi-hole.net
# Compiles a list of ad-serving domains by downloading them from multiple sources
#
# 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.
coltable="/opt/pihole/COL_TABLE"
source "${coltable}"
# Run this script as root or under sudo
echo ":::"
basename="pihole"
PIHOLE_COMMAND="/usr/local/bin/${basename}"
piholeDir="/etc/${basename}"
piholeRepo="/etc/.${basename}"
adListFile="${piholeDir}/adlists.list"
adListDefault="${piholeDir}/adlists.default"
adListRepoDefault="${piholeRepo}/adlists.default"
whitelistFile="${piholeDir}/whitelist.txt"
blacklistFile="${piholeDir}/blacklist.txt"
wildcardFile="/etc/dnsmasq.d/03-pihole-wildcard.conf"
adList="${piholeDir}/gravity.list"
blackList="${piholeDir}/black.list"
localList="${piholeDir}/local.list"
VPNList="/etc/openvpn/ipp.txt"
domainsExtension="domains"
matterAndLight="${basename}.0.matterandlight.txt"
parsedMatter="${basename}.1.parsedmatter.txt"
whitelistMatter="${basename}.2.whitelistmatter.txt"
accretionDisc="${basename}.3.accretionDisc.txt"
preEventHorizon="list.preEventHorizon"
skipDownload="false"
# Source setupVars from install script
setupVars="${piholeDir}/setupVars.conf"
if [[ -f "${setupVars}" ]];then
source "${setupVars}"
# Remove CIDR mask from IPv4/6 addresses
IPV4_ADDRESS="${IPV4_ADDRESS%/*}"
IPV6_ADDRESS="${IPV6_ADDRESS%/*}"
# Determine if IPv4/6 addresses exist
if [[ -z "${IPV4_ADDRESS}" ]] && [[ -z "${IPV6_ADDRESS}" ]]; then
echo -e " ${COL_LIGHT_RED}No IP addresses found! Please run 'pihole -r' to reconfigure${COL_NC}"
exit 1
fi
if [[ $EUID -eq 0 ]];then
echo "::: You are root."
else
echo -e " ${COL_LIGHT_RED}Installation Failure: ${setupVars} does not exist! ${COL_NC}
Please run 'pihole -r', and choose the 'reconfigure' option to fix."
exit 1
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
# Determine if superseded pihole.conf exists
if [[ -r "${piholeDir}/pihole.conf" ]]; then
echo -e " ${COL_LIGHT_RED}Ignoring overrides specified within pihole.conf! ${COL_NC}"
fi
# Determine if DNS resolution is available before proceeding
gravity_DNSLookup() {
local lookupDomain="pi.hole"
# Determine if $localList does not exist
if [[ ! -e "${localList}" ]]; then
lookupDomain="raw.githubusercontent.com"
fi
# Determine if $lookupDomain is resolvable
if timeout 1 getent hosts "${lookupDomain}" &> /dev/null; then
# Print confirmation of resolvability if it had previously failed
if [[ -n "${secs:-}" ]]; then
echo -e "${OVER} ${TICK} DNS resolution is now available\\n"
fi
return 0
elif [[ -n "${secs:-}" ]]; then
echo -e "${OVER} ${CROSS} DNS resolution is not available"
exit 1
fi
# If the /etc/resolv.conf contains resolvers other than 127.0.0.1 then the local dnsmasq will not be queried and pi.hole is NXDOMAIN.
# This means that even though name resolution is working, the getent hosts check fails and the holddown timer keeps ticking and eventualy fails
# So we check the output of the last command and if it failed, attempt to use dig +short as a fallback
if timeout 1 dig +short "${lookupDomain}" &> /dev/null; then
if [[ -n "${secs:-}" ]]; then
echo -e "${OVER} ${TICK} DNS resolution is now available\\n"
fi
return 0
elif [[ -n "${secs:-}" ]]; then
echo -e "${OVER} ${CROSS} DNS resolution is not available"
exit 1
fi
# Determine error output message
if pidof dnsmasq &> /dev/null; then
echo -e " ${CROSS} DNS resolution is currently unavailable"
else
echo -e " ${CROSS} DNS service is not running"
"${PIHOLE_COMMAND}" restartdns
fi
# Ensure DNS server is given time to be resolvable
secs="120"
echo -ne " ${INFO} Time until retry: ${secs}"
until timeout 1 getent hosts "${lookupDomain}" &> /dev/null; do
[[ "${secs:-}" -eq 0 ]] && break
echo -ne "${OVER} ${INFO} Time until retry: ${secs}"
: $((secs--))
sleep 1
done
# Try again
gravity_DNSLookup
}
# Retrieve blocklist URLs and parse domains from adlists.list
gravity_Collapse() {
echo -e " ${INFO} ${COL_BOLD}Neutrino emissions detected${COL_NC}..."
# Determine if adlists file needs handling
if [[ ! -f "${adListFile}" ]]; then
# Create "adlists.list" by copying "adlists.default" from internal core repo
cp "${adListRepoDefault}" "${adListFile}" 2> /dev/null || \
echo -e " ${CROSS} Unable to copy ${adListFile##*/} from ${piholeRepo}"
elif [[ -f "${adListDefault}" ]] && [[ -f "${adListFile}" ]]; then
# Remove superceded $adListDefault file
rm "${adListDefault}" 2> /dev/null || \
echo -e " ${CROSS} Unable to remove ${adListDefault}"
fi
local str="Pulling blocklist source list into range"
echo -ne " ${INFO} ${str}..."
# Retrieve source URLs from $adListFile
# Logic: Remove comments and empty lines
mapfile -t sources <<< "$(grep -v -E "^(#|$)" "${adListFile}" 2> /dev/null)"
# Parse source domains from $sources
mapfile -t sourceDomains <<< "$(
# Logic: Split by folder/port
awk -F '[/:]' '{
# Remove URL protocol & optional username:password@
gsub(/(.*:\/\/|.*:.*@)/, "", $0)
if(length($1)>0){print $1}
else {print "local"}
}' <<< "$(printf '%s\n' "${sources[@]}")" 2> /dev/null
)"
if [[ -n "${sources[*]}" ]] && [[ -n "${sourceDomains[*]}" ]]; then
echo -e "${OVER} ${TICK} ${str}"
else
echo -e "${OVER} ${CROSS} ${str}"
gravity_Cleanup "error"
fi
}
# Define options for when retrieving blocklists
gravity_Supernova() {
local url domain agent cmd_ext str
echo ""
# Loop through $sources and download each one
for ((i = 0; i < "${#sources[@]}"; i++)); do
url="${sources[$i]}"
domain="${sourceDomains[$i]}"
# Save the file as list.#.domain
saveLocation="${piholeDir}/list.${i}.${domain}.${domainsExtension}"
activeDomains[$i]="${saveLocation}"
# Default user-agent (for Cloudflare's Browser Integrity Check: https://support.cloudflare.com/hc/en-us/articles/200170086-What-does-the-Browser-Integrity-Check-do-)
agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36"
# Provide special commands for blocklists which may need them
case "${domain}" in
"pgl.yoyo.org") cmd_ext="-d mimetype=plaintext -d hostformat=hosts";;
*) cmd_ext="";;
esac
if [[ "${skipDownload}" == false ]]; then
echo -e " ${INFO} Target: ${domain} (${url##*/})"
gravity_Pull "${url}" "${cmd_ext}" "${agent}"
echo ""
fi
done
gravity_Blackbody=true
}
# Download specified URL and perform checks on HTTP status and file content
gravity_Pull() {
local url="${1}" cmd_ext="${2}" agent="${3}" heisenbergCompensator="" patternBuffer str httpCode success=""
# Create temp file to store content on disk instead of RAM
patternBuffer=$(mktemp -p "/tmp" --suffix=".phgpb")
# Determine if $saveLocation has read permission
if [[ -r "${saveLocation}" && $url != "file"* ]]; then
# Have curl determine if a remote file has been modified since last retrieval
# Uses "Last-Modified" header, which certain web servers do not provide (e.g: raw github urls)
# Note: Don't do this for local files, always download them
heisenbergCompensator="-z ${saveLocation}"
fi
str="Status:"
echo -ne " ${INFO} ${str} Pending..."
# shellcheck disable=SC2086
httpCode=$(curl -s -L ${cmd_ext} ${heisenbergCompensator} -w "%{http_code}" -A "${agent}" "${url}" -o "${patternBuffer}" 2> /dev/null)
case $url in
# Did we "download" a remote file?
"http"*)
# Determine "Status:" output based on HTTP response
case "${httpCode}" in
"200") echo -e "${OVER} ${TICK} ${str} Retrieval successful"; success=true;;
"304") echo -e "${OVER} ${TICK} ${str} No changes detected"; success=true;;
"000") echo -e "${OVER} ${CROSS} ${str} Connection Refused";;
"403") echo -e "${OVER} ${CROSS} ${str} Forbidden";;
"404") echo -e "${OVER} ${CROSS} ${str} Not found";;
"408") echo -e "${OVER} ${CROSS} ${str} Time-out";;
"451") echo -e "${OVER} ${CROSS} ${str} Unavailable For Legal Reasons";;
"500") echo -e "${OVER} ${CROSS} ${str} Internal Server Error";;
"504") echo -e "${OVER} ${CROSS} ${str} Connection Timed Out (Gateway)";;
"521") echo -e "${OVER} ${CROSS} ${str} Web Server Is Down (Cloudflare)";;
"522") echo -e "${OVER} ${CROSS} ${str} Connection Timed Out (Cloudflare)";;
* ) echo -e "${OVER} ${CROSS} ${str} ${httpCode}";;
esac;;
# Did we "download" a local file?
"file"*)
if [[ -s "${patternBuffer}" ]]; then
echo -e "${OVER} ${TICK} ${str} Retrieval successful"; success=true
else
echo -e "${OVER} ${CROSS} ${str} Not found / empty list"
fi;;
*) echo -e "${OVER} ${CROSS} ${str} ${url} ${httpCode}";;
esac
# Determine if the blocklist was downloaded and saved correctly
if [[ "${success}" == true ]]; then
if [[ "${httpCode}" == "304" ]]; then
: # Do not attempt to re-parse file
# Check if $patternbuffer is a non-zero length file
elif [[ -s "${patternBuffer}" ]]; then
# Determine if blocklist is non-standard and parse as appropriate
gravity_ParseFileIntoDomains "${patternBuffer}" "${saveLocation}"
else
# Fall back to previously cached list if $patternBuffer is empty
echo -e " ${INFO} Received empty file: ${COL_LIGHT_GREEN}using previously cached list${COL_NC}"
fi
else
# Determine if cached list has read permission
if [[ -r "${saveLocation}" ]]; then
echo -e " ${CROSS} List download failed: ${COL_LIGHT_GREEN}using previously cached list${COL_NC}"
else
echo -e " ${CROSS} List download failed: ${COL_LIGHT_RED}no cached list available${COL_NC}"
fi
fi
}
# Parse source files into domains format
gravity_ParseFileIntoDomains() {
local source="${1}" destination="${2}" firstLine abpFilter
# Determine if we are parsing a consolidated list
if [[ "${source}" == "${piholeDir}/${matterAndLight}" ]]; then
# Remove comments and print only the domain name
# Most of the lists downloaded are already in hosts file format but the spacing/formating is not contigious
# This helps with that and makes it easier to read
# It also helps with debugging so each stage of the script can be researched more in depth
#Awk -F splits on given IFS, we grab the right hand side (chops trailing #coments and /'s to grab the domain only.
#Last awk command takes non-commented lines and if they have 2 fields, take the left field (the domain) and leave
#+ the right (IP address), otherwise grab the single field.
< ${source} awk -F '#' '{print $1}' | \
awk -F '/' '{print $1}' | \
awk '($1 !~ /^#/) { if (NF>1) {print $2} else {print $1}}' | \
sed -nr -e 's/\.{2,}/./g' -e '/\./p' > ${destination}
return 0
fi
# Individual file parsing: Keep comments, while parsing domains from each line
# We keep comments to respect the list maintainer's licensing
read -r firstLine < "${source}"
# Determine how to parse individual source file formats
if [[ "${firstLine,,}" =~ (adblock|ublock|^!) ]]; then
# Compare $firstLine against lower case words found in Adblock lists
echo -ne " ${INFO} Format: Adblock"
# Define symbols used as comments: [!
# "||.*^" includes the "Example 2" domains we can extract
# https://adblockplus.org/filter-cheatsheet
abpFilter="/^(\\[|!)|^(\\|\\|.*\\^)/"
# Parse Adblock lists by extracting "Example 2" domains
# Logic: Ignore lines which do not include comments or domain name anchor
awk ''"${abpFilter}"' {
# Remove valid adblock type options
gsub(/\$?~?(important|third-party|popup|subdocument|websocket),?/, "", $0)
# Remove starting domain name anchor "||" and ending seperator "^"
gsub(/^(\|\|)|(\^)/, "", $0)
# Remove invalid characters (*/,=$)
if($0 ~ /[*\/,=\$]/) { $0="" }
# Remove lines which are only IPv4 addresses
if($0 ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) { $0="" }
if($0) { print $0 }
}' "${source}" > "${destination}"
# Determine if there are Adblock exception rules
# https://adblockplus.org/filters
if grep -q "^@@||" "${source}" &> /dev/null; then
# Parse Adblock lists by extracting exception rules
# Logic: Ignore lines which do not include exception format "@@||example.com^"
awk -F "[|^]" '/^@@\|\|.*\^/ {
# Remove valid adblock type options
gsub(/\$?~?(third-party)/, "", $0)
# Remove invalid characters (*/,=$)
if($0 ~ /[*\/,=\$]/) { $0="" }
if($3) { print $3 }
}' "${source}" > "${destination}.exceptionsFile.tmp"
# Remove exceptions
grep -F -x -v -f "${destination}.exceptionsFile.tmp" "${destination}" > "${source}"
mv "${source}" "${destination}"
fi
echo -e "${OVER} ${TICK} Format: Adblock"
elif grep -q "^address=/" "${source}" &> /dev/null; then
# Parse Dnsmasq format lists
echo -e " ${CROSS} Format: Dnsmasq (list type not supported)"
elif grep -q -E "^https?://" "${source}" &> /dev/null; then
# Parse URL list if source file contains "http://" or "https://"
# Scanning for "^IPv4$" is too slow with large (1M) lists on low-end hardware
echo -ne " ${INFO} Format: URL"
awk '{
# Remove URL protocol, optional "username:password@", and ":?/;"
if ($0 ~ /[:?\/;]/) { gsub(/(^.*:\/\/(.*:.*@)?|[:?\/;].*)/, "", $0) }
# Remove lines which are only IPv4 addresses
if ($0 ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) { $0="" }
if ($0) { print $0 }
}' "${source}" 2> /dev/null > "${destination}"
echo -e "${OVER} ${TICK} Format: URL"
else
# Default: Keep hosts/domains file in same format as it was downloaded
output=$( { mv "${source}" "${destination}"; } 2>&1 )
if [[ ! -e "${destination}" ]]; then
echo -e "\\n ${CROSS} Unable to move tmp file to ${piholeDir}
${output}"
gravity_Cleanup "error"
fi
fi
}
# Create (unfiltered) "Matter and Light" consolidated list
gravity_Schwarzschild() {
local str lastLine
str="Consolidating blocklists"
echo -ne " ${INFO} ${str}..."
# Empty $matterAndLight if it already exists, otherwise, create it
: > "${piholeDir}/${matterAndLight}"
# Loop through each *.domains file
for i in "${activeDomains[@]}"; do
# Determine if file has read permissions, as download might have failed
if [[ -r "${i}" ]]; then
# Remove windows CRs from file, convert list to lower case, and append into $matterAndLight
tr -d '\r' < "${i}" | tr '[:upper:]' '[:lower:]' >> "${piholeDir}/${matterAndLight}"
# Ensure that the first line of a new list is on a new line
lastLine=$(tail -1 "${piholeDir}/${matterAndLight}")
if [[ "${#lastLine}" -gt 0 ]]; then
echo "" >> "${piholeDir}/${matterAndLight}"
fi
fi
done
echo -e "${OVER} ${TICK} ${str}"
}
# Parse consolidated list into (filtered, unique) domains-only format
gravity_Filter() {
local str num
str="Extracting domains from blocklists"
echo -ne " ${INFO} ${str}..."
# Parse into hosts file
gravity_ParseFileIntoDomains "${piholeDir}/${matterAndLight}" "${piholeDir}/${parsedMatter}"
# Format $parsedMatter line total as currency
num=$(printf "%'.0f" "$(wc -l < "${piholeDir}/${parsedMatter}")")
echo -e "${OVER} ${TICK} ${str}
${INFO} Number of domains being pulled in by gravity: ${COL_BLUE}${num}${COL_NC}"
str="Removing duplicate domains"
echo -ne " ${INFO} ${str}..."
sort -u "${piholeDir}/${parsedMatter}" > "${piholeDir}/${preEventHorizon}"
echo -e "${OVER} ${TICK} ${str}"
# Format $preEventHorizon line total as currency
num=$(printf "%'.0f" "$(wc -l < "${piholeDir}/${preEventHorizon}")")
echo -e " ${INFO} Number of unique domains trapped in the Event Horizon: ${COL_BLUE}${num}${COL_NC}"
}
# Whitelist unique blocklist domain sources
gravity_WhitelistBLD() {
local uniqDomains str
echo ""
# Create array of unique $sourceDomains
mapfile -t uniqDomains <<< "$(awk '{ if(!a[$1]++) { print $1 } }' <<< "$(printf '%s\n' "${sourceDomains[@]}")")"
str="Number of blocklist source domains being added to the whitelist: ${#uniqDomains[@]}"
echo -ne " ${INFO} ${str}..."
# Whitelist $uniqDomains
"${PIHOLE_COMMAND}" -w -nr -q ${uniqDomains[*]} &> /dev/null
echo -e "${OVER} ${INFO} ${str}"
}
# Whitelist user-defined domains
gravity_Whitelist() {
local num str
if [[ ! -f "${whitelistFile}" ]]; then
echo -e " ${INFO} Nothing to whitelist!"
return 0
fi
num=$(wc -l < "${whitelistFile}")
str="Number of whitelisted domains: ${num}"
echo -ne " ${INFO} ${str}..."
# Print everything from preEventHorizon into whitelistMatter EXCEPT domains in $whitelistFile
grep -F -x -v -f "${whitelistFile}" "${piholeDir}/${preEventHorizon}" > "${piholeDir}/${whitelistMatter}"
echo -e "${OVER} ${INFO} ${str}"
}
# Output count of blacklisted domains and wildcards
gravity_ShowBlockCount() {
local num
if [[ -f "${blacklistFile}" ]]; then
num=$(printf "%'.0f" "$(wc -l < "${blacklistFile}")")
echo -e " ${INFO} Number of blacklisted domains: ${num}"
fi
if [[ -f "${wildcardFile}" ]]; then
num=$(grep -c "^" "${wildcardFile}")
# If IPv4 and IPv6 is used, divide total wildcard count by 2
if [[ -n "${IPV4_ADDRESS}" ]] && [[ -n "${IPV6_ADDRESS}" ]];then
num=$(( num/2 ))
fi
echo -e " ${INFO} Number of wildcard blocked domains: ${num}"
fi
}
# Parse list of domains into hosts format
gravity_ParseDomainsIntoHosts() {
awk -v ipv4="$IPV4_ADDRESS" -v ipv6="$IPV6_ADDRESS" '{
# Remove windows CR line endings
sub(/\r$/, "")
# Parse each line as "ipaddr domain"
if(ipv6 && ipv4) {
print ipv4" "$0"\n"ipv6" "$0
} else if(!ipv6) {
print ipv4" "$0
} else {
print ipv6" "$0
}
}' >> "${2}" < "${1}"
}
# Create "localhost" entries into hosts format
gravity_ParseLocalDomains() {
local hostname
if [[ -s "/etc/hostname" ]]; then
hostname=$(< "/etc/hostname")
elif command -v hostname &> /dev/null; then
hostname=$(hostname -f)
else
echo -e " ${CROSS} Unable to determine fully qualified domain name of host"
return 0
fi
echo -e "${hostname}\\npi.hole" > "${localList}.tmp"
# Empty $localList if it already exists, otherwise, create it
: > "${localList}"
gravity_ParseDomainsIntoHosts "${localList}.tmp" "${localList}"
# Add additional LAN hosts provided by OpenVPN (if available)
if [[ -f "${VPNList}" ]]; then
awk -F, '{printf $2"\t"$1".vpn\n"}' "${VPNList}" >> "${localList}"
fi
}
# Create primary blacklist entries
gravity_ParseBlacklistDomains() {
local output status
# Empty $accretionDisc if it already exists, otherwise, create it
: > "${piholeDir}/${accretionDisc}"
gravity_ParseDomainsIntoHosts "${piholeDir}/${whitelistMatter}" "${piholeDir}/${accretionDisc}"
# Move the file over as /etc/pihole/gravity.list so dnsmasq can use it
output=$( { mv "${piholeDir}/${accretionDisc}" "${adList}"; } 2>&1 )
status="$?"
if [[ "${status}" -ne 0 ]]; then
echo -e "\\n ${CROSS} Unable to move ${accretionDisc} from ${piholeDir}\\n ${output}"
gravity_Cleanup "error"
fi
}
# Create user-added blacklist entries
gravity_ParseUserDomains() {
if [[ ! -f "${blacklistFile}" ]]; then
return 0
fi
gravity_ParseDomainsIntoHosts "${blacklistFile}" "${blackList}.tmp"
# Copy the file over as /etc/pihole/black.list so dnsmasq can use it
mv "${blackList}.tmp" "${blackList}" 2> /dev/null || \
echo -e "\\n ${CROSS} Unable to move ${blackList##*/}.tmp to ${piholeDir}"
}
# Trap Ctrl-C
gravity_Trap() {
trap '{ echo -e "\\n\\n ${INFO} ${COL_LIGHT_RED}User-abort detected${COL_NC}"; gravity_Cleanup "error"; }' INT
}
# Clean up after Gravity upon exit or cancellation
gravity_Cleanup() {
local error="${1:-}"
str="Cleaning up stray matter"
echo -ne " ${INFO} ${str}..."
# Delete tmp content generated by Gravity
rm ${piholeDir}/pihole.*.txt 2> /dev/null
rm ${piholeDir}/*.tmp 2> /dev/null
rm /tmp/*.phgpb 2> /dev/null
# Ensure this function only runs when gravity_Supernova() has completed
if [[ "${gravity_Blackbody:-}" == true ]]; then
# Remove any unused .domains files
for file in ${piholeDir}/*.${domainsExtension}; do
# If list is not in active array, then remove it
if [[ ! "${activeDomains[*]}" == *"${file}"* ]]; then
rm -f "${file}" 2> /dev/null || \
echo -e " ${CROSS} Failed to remove ${file##*/}"
fi
done
fi
echo -e "${OVER} ${TICK} ${str}"
# Only restart DNS service if offline
if ! pidof dnsmasq &> /dev/null; then
"${PIHOLE_COMMAND}" restartdns
dnsWasOffline=true
fi
# Print Pi-hole status if an error occured
if [[ -n "${error}" ]]; then
"${PIHOLE_COMMAND}" status
exit 1
fi
}
helpFunc() {
echo "Usage: pihole -g
Update domains from blocklists specified in adlists.list
Options:
-f, --force Force the download of all specified blocklists
-h, --help Show this help dialog"
exit 0
}
for var in "$@"; do
case "${var}" in
"-f" | "--force" ) forceDelete=true;;
"-h" | "--help" ) helpFunc;;
"-sd" | "--skip-download" ) skipDownload=true;;
"-b" | "--blacklist-only" ) listType="blacklist";;
"-w" | "--whitelist-only" ) listType="whitelist";;
"-wild" | "--wildcard-only" ) listType="wildcard"; dnsRestartType="restart";;
esac
done
# Trap Ctrl-C
gravity_Trap
if [[ "${forceDelete:-}" == true ]]; then
str="Deleting existing list cache"
echo -ne "${INFO} ${str}..."
rm /etc/pihole/list.* 2> /dev/null || true
echo -e "${OVER} ${TICK} ${str}"
fi
# Determine which functions to run
if [[ "${skipDownload}" == false ]]; then
# Gravity needs to download blocklists
gravity_DNSLookup
gravity_Collapse
gravity_Supernova
gravity_Schwarzschild
gravity_Filter
gravity_WhitelistBLD
piholeIPfile=/etc/pihole/piholeIP
piholeIPv6file=/etc/pihole/.useIPv6
adListFile=/etc/pihole/adlists.list
adListDefault=/etc/pihole/adlists.default
whitelistScript=/opt/pihole/whitelist.sh
blacklistScript=/opt/pihole/blacklist.sh
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
# Gravity needs to modify Blacklist/Whitelist/Wildcards
echo -e " ${INFO} Using cached Event Horizon list..."
numberOf=$(printf "%'.0f" "$(wc -l < "${piholeDir}/${preEventHorizon}")")
echo -e " ${INFO} ${COL_BLUE}${numberOf}${COL_NC} unique domains trapped in the Event Horizon"
# 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
# Perform when downloading blocklists, or modifying the whitelist
if [[ "${skipDownload}" == false ]] || [[ "${listType}" == "whitelist" ]]; then
gravity_Whitelist
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
gravity_ShowBlockCount
# Variables for various stages of downloading and formatting the list
## Nate 3/26/2016 - Commented unused variables
basename=pihole
piholeDir=/etc/$basename
adList=$piholeDir/gravity.list
#blacklist=$piholeDir/blacklist.txt
#whitelist=$piholeDir/whitelist.txt
#latentWhitelist=$piholeDir/latentWhitelist.txt
justDomainsExtension=domains
matterandlight=$basename.0.matterandlight.txt
supernova=$basename.1.supernova.txt
eventHorizon=$basename.2.eventHorizon.txt
accretionDisc=$basename.3.accretionDisc.txt
#eyeOfTheNeedle=$basename.4.wormhole.txt
# Perform when downloading blocklists, or modifying the white/blacklist (not wildcards)
if [[ "${skipDownload}" == false ]] || [[ "${listType}" == *"list" ]]; then
str="Parsing domains into hosts format"
echo -ne " ${INFO} ${str}..."
gravity_ParseUserDomains
# Perform when downloading blocklists
if [[ ! "${listType:-}" == "blacklist" ]]; then
gravity_ParseLocalDomains
gravity_ParseBlacklistDomains
fi
echo -e "${OVER} ${TICK} ${str}"
gravity_Cleanup
# After setting defaults, check if there's local overrides
if [[ -r $piholeDir/pihole.conf ]];then
echo "::: Local calibration requested..."
. $piholeDir/pihole.conf
fi
echo ""
###########################
# collapse - begin formation of pihole
function gravity_collapse() {
echo "::: Neutrino emissions detected..."
echo ":::"
#Decide if we're using a custom ad block list, or defaults.
if [ -f $adListFile ]; then
#custom file found, use this instead of default
echo -n "::: Custom adList file detected. Reading..."
sources=()
while read -r line; do
#Do not read commented out or blank lines
if [[ $line = \#* ]] || [[ ! $line ]]; then
echo "" > /dev/null
else
sources+=($line)
fi
done < $adListFile
echo " done!"
else
#no custom file found, use defaults!
echo -n "::: No custom adlist file detected, reading from default file..."
sources=()
while read -r line; do
#Do not read commented out or blank lines
if [[ $line = \#* ]] || [[ ! $line ]]; then
echo "" > /dev/null
else
sources+=($line)
fi
done < $adListDefault
echo " done!"
fi
# Determine if DNS has been restarted by this instance of gravity
if [[ -z "${dnsWasOffline:-}" ]]; then
# Use "force-reload" when restarting dnsmasq for everything but Wildcards
"${PIHOLE_COMMAND}" restartdns "${dnsRestartType:-force-reload}"
fi
"${PIHOLE_COMMAND}" status
# Create the pihole resource directory if it doesn't exist. Future files will be stored here
if [[ -d $piholeDir ]];then
# Temporary hack to allow non-root access to pihole directory
# Will update later, needed for existing installs, new installs should
# create this directory as non-root
$SUDO chmod 777 $piholeDir
echo ":::"
echo "::: Existing pihole directory found"
else
echo "::: Creating pihole directory..."
mkdir $piholeDir
$SUDO chmod 777 $piholeDir
fi
}
# patternCheck - check to see if curl downloaded any new files.
function gravity_patternCheck() {
patternBuffer=$1
# check if the patternbuffer is a non-zero length file
if [[ -s "$patternBuffer" ]];then
# Some of the blocklists are copyright, they need to be downloaded
# and stored as is. They can be processed for content after they
# have been saved.
cp "$patternBuffer" "$saveLocation"
echo " List updated, transport successful!"
else
# curl didn't download any host files, probably because of the date check
echo " No changes detected, transport skipped!"
fi
}
# transport - curl the specified url with any needed command extentions
function gravity_transport() {
url=$1
cmd_ext=$2
agent=$3
# tmp file, so we don't have to store the (long!) lists in RAM
patternBuffer=$(mktemp)
heisenbergCompensator=""
if [[ -r $saveLocation ]]; then
# if domain has been saved, add file for date check to only download newer
heisenbergCompensator="-z $saveLocation"
fi
# Silently curl url
curl -s $cmd_ext $heisenbergCompensator -A "$agent" $url > $patternBuffer
# Check for list updates
gravity_patternCheck "$patternBuffer"
# Cleanup
rm -f "$patternBuffer"
}
# spinup - main gravity function
function gravity_spinup() {
echo ":::"
# Loop through domain list. Download each one and remove commented lines (lines beginning with '# 'or '/') and # blank lines
for ((i = 0; i < "${#sources[@]}"; i++))
do
url=${sources[$i]}
# Get just the domain from the URL
domain=$(echo "$url" | cut -d'/' -f3)
# Save the file as list.#.domain
saveLocation=$piholeDir/list.$i.$domain.$justDomainsExtension
activeDomains[$i]=$saveLocation
agent="Mozilla/10.0"
echo -n "::: Getting $domain list..."
# Use a case statement to download lists that need special cURL commands
# to complete properly and reset the user agent when required
case "$domain" in
"adblock.mahakala.is")
agent='Mozilla/5.0 (X11; Linux x86_64; rv:30.0) Gecko/20100101 Firefox/30.0'
cmd_ext="-e http://forum.xda-developers.com/"
;;
"pgl.yoyo.org")
cmd_ext="-d mimetype=plaintext -d hostformat=hosts"
;;
# Default is a simple request
*) cmd_ext=""
esac
gravity_transport "$url" "$cmd_ext" "$agent"
done
}
# Schwarzchild - aggregate domains to one list and add blacklisted domains
function gravity_Schwarzchild() {
echo "::: "
# Find all active domains and compile them into one file and remove CRs
echo -n "::: Aggregating list of domains..."
truncate -s 0 $piholeDir/$matterandlight
for i in "${activeDomains[@]}"
do
cat "$i" | tr -d '\r' >> $piholeDir/$matterandlight
done
echo " done!"
}
function gravity_Blacklist(){
# Append blacklist entries if they exist
echo -n "::: Running blacklist script to update HOSTS file...."
$blacklistScript -f -nr -q > /dev/null
numBlacklisted=$(wc -l < "/etc/pihole/blacklist.txt")
plural=; [[ "$numBlacklisted" != "1" ]] && plural=s
echo " $numBlacklisted domain${plural} blacklisted!"
}
function gravity_Whitelist() {
echo ":::"
# Prevent our sources from being pulled into the hole
plural=; [[ "${sources[@]}" != "1" ]] && plural=s
echo -n "::: Adding ${#sources[@]} adlist source${plural} to the whitelist..."
urls=()
for url in "${sources[@]}"
do
tmp=$(echo "$url" | awk -F '/' '{print $3}')
urls=("${urls[@]}" $tmp)
done
echo " done!"
echo -n "::: Running whitelist script to update HOSTS file...."
$whitelistScript -f -nr -q "${urls[@]}" > /dev/null
numWhitelisted=$(wc -l < "/etc/pihole/whitelist.txt")
plural=; [[ "$numWhitelisted" != "1" ]] && plural=s
echo " $numWhitelisted domain${plural} whitelisted!"
}
function gravity_unique() {
# Sort and remove duplicates
echo -n "::: Removing duplicate domains...."
sort -u $piholeDir/$supernova > $piholeDir/$eventHorizon
echo " done!"
numberOf=$(wc -l < $piholeDir/$eventHorizon)
echo "::: $numberOf unique domains trapped in the event horizon."
}
function gravity_hostFormat() {
# Format domain list as "192.168.x.x domain.com"
echo "::: Formatting domains into a HOSTS file..."
hostname=$(</etc/hostname)
# If there is a value in the $piholeIPv6, then IPv6 will be used, so the awk command modified to create a line for both protocols
if [[ -n $piholeIPv6 ]];then
# Add hostname and dummy domain to the top of gravity.list to make ping result return a friendlier looking domain! Also allows for an easy way to access the Pi-hole admin console (pi.hole/admin)
echo -e "$piholeIP $hostname\n$piholeIPv6 $hostname\n$piholeIP pi.hole\n$piholeIPv6 pi.hole" > $piholeDir/$accretionDisc
cat $piholeDir/$eventHorizon | awk -v ipv4addr="$piholeIP" -v ipv6addr="$piholeIPv6" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> $piholeDir/$accretionDisc
else
# Otherwise, just create gravity.list as normal using IPv4
# Add hostname and dummy domain to the top of gravity.list to make ping result return a friendlier looking domain! Also allows for an easy way to access the Pi-hole admin console (pi.hole/admin)
echo -e "$piholeIP $hostname\n$piholeIP pi.hole" > $piholeDir/$accretionDisc
cat $piholeDir/$eventHorizon | awk -v ipv4addr="$piholeIP" '{sub(/\r$/,""); print ipv4addr" "$0}' >> $piholeDir/$accretionDisc
fi
# Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it
cp $piholeDir/$accretionDisc $adList
}
# blackbody - remove any remnant files from script processes
function gravity_blackbody() {
# Loop through list files
for file in $piholeDir/*.$justDomainsExtension
do
# If list is in active array then leave it (noop) else rm the list
if [[ " ${activeDomains[@]} " =~ ${file} ]]; then
:
else
rm -f "$file"
fi
done
}
function gravity_advanced() {
# Remove comments and print only the domain name
# Most of the lists downloaded are already in hosts file format but the spacing/formating is not contigious
# This helps with that and makes it easier to read
# It also helps with debugging so each stage of the script can be researched more in depth
echo -n "::: Formatting list of domains to remove comments...."
awk '($1 !~ /^#/) { if (NF>1) {print $2} else {print $1}}' $piholeDir/$matterandlight | sed -nr -e 's/\.{2,}/./g' -e '/\./p' > $piholeDir/$supernova
echo " done!"
numberOf=$(wc -l < $piholeDir/$supernova)
echo "::: $numberOf domains being pulled in by gravity..."
gravity_unique
}
function gravity_reload() {
#Clear no longer needed files...
echo ":::"
echo -n "::: Cleaning up un-needed files..."
$SUDO rm $piholeDir/pihole.*.txt
echo " done!"
# Reload hosts file
echo ":::"
echo -n "::: Refresh lists in dnsmasq..."
#ensure /etc/dnsmasq.d/01-pihole.conf is pointing at the correct list!
#First escape forward slashes in the path:
adList=${adList//\//\\\/}
#Now replace the line in dnsmasq file
$SUDO sed -i "s/^addn-hosts.*/addn-hosts=$adList/" /etc/dnsmasq.d/01-pihole.conf
dnsmasqPid=$(pidof dnsmasq)
find "$piholeDir" -type f -exec $SUDO chmod 666 {} \;
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!"
}
$SUDO cp /etc/.pihole/adlists.default /etc/pihole/adlists.default
gravity_collapse
gravity_spinup
gravity_Schwarzchild
gravity_advanced
gravity_hostFormat
gravity_blackbody
gravity_Whitelist
gravity_Blacklist
gravity_reload

704
pihole
View File

@@ -1,663 +1,121 @@
#!/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.
readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
readonly colfile="${PI_HOLE_SCRIPT_DIR}/COL_TABLE"
source "${colfile}"
# 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
if [[ -x "$(command -v sudo)" ]]; then
exec sudo bash "$0" "$@"
exit $?
#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 -e " ${CROSS} sudo is needed to run pihole commands. Please run this script as root or install sudo."
echo "::: Please install sudo or run this as root."
exit 1
fi
fi
webpageFunc() {
source "${PI_HOLE_SCRIPT_DIR}/webpage.sh"
main "$@"
exit 0
function whitelistFunc {
shift
$SUDO /opt/pihole/whitelist.sh "$@"
exit 1
}
whitelistFunc() {
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
exit 0
function blacklistFunc {
shift
$SUDO /opt/pihole/blacklist.sh "$@"
exit 1
}
blacklistFunc() {
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
exit 0
function debugFunc {
$SUDO /opt/pihole/piholeDebug.sh
exit 1
}
wildcardFunc() {
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
exit 0
function flushFunc {
$SUDO /opt/pihole/piholeLogFlush.sh
exit 1
}
debugFunc() {
local automated
local web
# Pull off the `debug` leaving passed call augmentation flags in $1
shift
if [[ "$@" == *"-a"* ]]; then
automated="true"
fi
if [[ "$@" == *"-w"* ]]; then
web="true"
fi
AUTOMATED=${automated:-} WEBCALL=${web:-} "${PI_HOLE_SCRIPT_DIR}"/piholeDebug.sh
exit 0
function updateDashboardFunc {
$SUDO /opt/pihole/updateDashboard.sh
exit 1
}
flushFunc() {
"${PI_HOLE_SCRIPT_DIR}"/piholeLogFlush.sh "$@"
exit 0
function updateGravityFunc {
$SUDO /opt/pihole/gravity.sh
exit 1
}
updatePiholeFunc() {
"${PI_HOLE_SCRIPT_DIR}"/update.sh
exit 0
function updatePiholeFunc {
$SUDO /opt/pihole/updatePihole.sh
exit 1
}
reconfigurePiholeFunc() {
/etc/.pihole/automated\ install/basic-install.sh --reconfigure
exit 0;
function setupLCDFunction {
$SUDO /opt/pihole/setupLCD.sh
exit 1
}
updateGravityFunc() {
"${PI_HOLE_SCRIPT_DIR}"/gravity.sh "$@"
exit 0
}
# Scan an array of files for matching strings
scanList(){
# Escape full stops
local domain="${1//./\\.}" lists="${2}" type="${3:-}"
# Prevent grep from printing file path
cd "/etc/pihole" || exit 1
# Prevent grep -i matching slowly: http://bit.ly/2xFXtUX
export LC_CTYPE=C
# /dev/null forces filename to be printed when only one list has been generated
# shellcheck disable=SC2086
case "${type}" in
"exact" ) grep -i -E -l "(^|\\s)${domain}($|\\s|#)" ${lists} /dev/null;;
"wc" ) grep -i -o -m 1 "/${domain}/" ${lists};;
* ) grep -i "${domain}" ${lists} /dev/null;;
esac
}
# Print each subdomain
# e.g: foo.bar.baz.com = "foo.bar.baz.com bar.baz.com baz.com com"
processWildcards() {
IFS="." read -r -a array <<< "${1}"
for (( i=${#array[@]}-1; i>=0; i-- )); do
ar=""
for (( j=${#array[@]}-1; j>${#array[@]}-i-2; j-- )); do
if [[ $j == $((${#array[@]}-1)) ]]; then
ar="${array[$j]}"
else
ar="${array[$j]}.${ar}"
fi
done
echo "${ar}"
done
}
queryFunc() {
shift
local options="$*" adlist="" all="" exact="" blockpage="" matchType="match"
if [[ "${options}" == "-h" ]] || [[ "${options}" == "--help" ]]; then
echo "Usage: pihole -q [option] <domain>
Example: 'pihole -q -exact domain.com'
Query the adlists for a specified domain
Options:
-adlist Print the name of the block list URL
-exact Search the block lists for exact domain matches
-all Return all query matches within a block list
-h, --help Show this help dialog"
exit 0
fi
if [[ ! -e "/etc/pihole/adlists.list" ]]; then
echo -e "${COL_LIGHT_RED}The file '/etc/pihole/adlists.list' was not found${COL_NC}"
exit 1
fi
# Handle valid options
if [[ "${options}" == *"-bp"* ]]; then
exact="exact"; blockpage=true
else
[[ "${options}" == *"-adlist"* ]] && adlist=true
[[ "${options}" == *"-all"* ]] && all=true
if [[ "${options}" == *"-exact"* ]]; then
exact="exact"; matchType="exact ${matchType}"
fi
fi
# Strip valid options, leaving only the domain and invalid options
# This allows users to place the options before or after the domain
options=$(sed -E 's/ ?-(bp|adlists?|all|exact) ?//g' <<< "${options}")
# Handle remaining options
# If $options contain non ASCII characters, convert to punycode
case "${options}" in
"" ) str="No domain specified";;
*" "* ) str="Unknown query option specified";;
*[![:ascii:]]* ) domainQuery=$(idn2 "${options}");;
* ) domainQuery="${options}";;
esac
if [[ -n "${str:-}" ]]; then
echo -e "${str}${COL_NC}\\nTry 'pihole -q --help' for more information."
exit 1
fi
# Scan Whitelist and Blacklist
lists="whitelist.txt blacklist.txt"
mapfile -t results <<< "$(scanList "${domainQuery}" "${lists}" "${exact}")"
if [[ -n "${results[*]}" ]]; then
wbMatch=true
# Loop through each result in order to print unique file title once
for result in "${results[@]}"; do
fileName="${result%%.*}"
if [[ -n "${blockpage}" ]]; then
echo "π ${result}"
exit 0
elif [[ -n "${exact}" ]]; then
echo " ${matchType^} found in ${COL_BOLD}${fileName^}${COL_NC}"
else
# Only print filename title once per file
if [[ ! "${fileName}" == "${fileName_prev:-}" ]]; then
echo " ${matchType^} found in ${COL_BOLD}${fileName^}${COL_NC}"
fileName_prev="${fileName}"
fi
echo " ${result#*:}"
fi
done
fi
# Scan Wildcards
if [[ -e "${wildcardlist}" ]]; then
# Determine all subdomains, domain and TLDs
mapfile -t wildcards <<< "$(processWildcards "${domainQuery}")"
for match in "${wildcards[@]}"; do
# Search wildcard list for matches
mapfile -t results <<< "$(scanList "${match}" "${wildcardlist}" "wc")"
if [[ -n "${results[*]}" ]]; then
if [[ -z "${wcMatch:-}" ]] && [[ -z "${blockpage}" ]]; then
wcMatch=true
echo " ${matchType^} found in ${COL_BOLD}Wildcards${COL_NC}:"
fi
case "${blockpage}" in
true ) echo "π ${wildcardlist##*/}"; exit 0;;
* ) echo " *.${match}";;
esac
fi
done
fi
# Get version sorted *.domains filenames (without dir path)
lists=("$(cd "/etc/pihole" || exit 0; printf "%s\\n" -- *.domains | sort -V)")
# Query blocklists for occurences of domain
mapfile -t results <<< "$(scanList "${domainQuery}" "${lists[*]}" "${exact}")"
# Handle notices
if [[ -z "${wbMatch:-}" ]] && [[ -z "${wcMatch:-}" ]] && [[ -z "${results[*]}" ]]; then
echo -e " ${INFO} No ${exact/t/t }results found for ${COL_BOLD}${domainQuery}${COL_NC} found within block lists"
exit 0
elif [[ -z "${results[*]}" ]]; then
# Result found in WL/BL/Wildcards
exit 0
elif [[ -z "${all}" ]] && [[ "${#results[*]}" -ge 100 ]]; then
echo -e " ${INFO} Over 100 ${exact/t/t }results found for ${COL_BOLD}${domainQuery}${COL_NC}
This can be overridden using the -all option"
exit 0
fi
# Remove unwanted content from non-exact $results
if [[ -z "${exact}" ]]; then
# Delete lines starting with #
# Remove comments after domain
# Remove hosts format IP address
mapfile -t results <<< "$(IFS=$'\n'; sed \
-e "/:#/d" \
-e "s/[ \\t]#.*//g" \
-e "s/:.*[ \\t]/:/g" \
<<< "${results[*]}")"
# Exit if result was in a comment
[[ -z "${results[*]}" ]] && exit 0
fi
# Get adlist file content as array
if [[ -n "${adlist}" ]] || [[ -n "${blockpage}" ]]; then
for adlistUrl in $(< "/etc/pihole/adlists.list"); do
if [[ "${adlistUrl:0:4}" =~ (http|www.) ]]; then
adlists+=("${adlistUrl}")
fi
done
fi
# Print "Exact matches for" title
if [[ -n "${exact}" ]] && [[ -z "${blockpage}" ]]; then
plural=""; [[ "${#results[*]}" -gt 1 ]] && plural="es"
echo " ${matchType^}${plural} for ${COL_BOLD}${domainQuery}${COL_NC} found in:"
fi
for result in "${results[@]}"; do
fileName="${result/:*/}"
# Determine *.domains URL using filename's number
if [[ -n "${adlist}" ]] || [[ -n "${blockpage}" ]]; then
fileNum="${fileName/list./}"; fileNum="${fileNum%%.*}"
fileName="${adlists[$fileNum]}"
# Discrepency occurs when adlists has been modified, but Gravity has not been run
if [[ -z "${fileName}" ]]; then
fileName="${COL_LIGHT_RED}(no associated adlists URL found)${COL_NC}"
fi
fi
if [[ -n "${blockpage}" ]]; then
echo "${fileNum} ${fileName}"
elif [[ -n "${exact}" ]]; then
echo " ${fileName}"
else
if [[ ! "${fileName}" == "${fileName_prev:-}" ]]; then
count=""
echo " ${matchType^} found in ${COL_BOLD}${fileName}${COL_NC}:"
fileName_prev="${fileName}"
fi
: $((count++))
# Print matching domain if $max_count has not been reached
[[ -z "${all}" ]] && max_count="50"
if [[ -z "${all}" ]] && [[ "${count}" -ge "${max_count}" ]]; then
[[ "${count}" -gt "${max_count}" ]] && continue
echo " ${COL_GRAY}Over ${count} results found, skipping rest of file${COL_NC}"
else
echo " ${result#*:}"
fi
fi
done
exit 0
}
chronometerFunc() {
shift
"${PI_HOLE_SCRIPT_DIR}"/chronometer.sh "$@"
exit 0
function chronometerFunc {
shift
$SUDO /opt/pihole/chronometer.sh "$@"
exit 1
}
uninstallFunc() {
"${PI_HOLE_SCRIPT_DIR}"/uninstall.sh
exit 0
function uninstallFunc {
$SUDO /opt/pihole/uninstall.sh
exit 1
}
versionFunc() {
shift
"${PI_HOLE_SCRIPT_DIR}"/version.sh "$@"
exit 0
}
restartDNS() {
local svcOption svc str output status
svcOption="${1:-}"
# Determine if we should reload or restart dnsmasq
if [[ "${svcOption}" =~ "reload" ]]; then
# Using SIGHUP will NOT re-read any *.conf files
svc="killall -s SIGHUP dnsmasq"
else
# Get PID of dnsmasq to determine if it needs to start or restart
if pidof dnsmasq &> /dev/null; then
svcOption="restart"
else
svcOption="start"
fi
svc="service dnsmasq ${svcOption}"
fi
# Print output to Terminal, but not to Web Admin
str="${svcOption^}ing DNS service"
[[ -t 1 ]] && echo -ne " ${INFO} ${str}..."
output=$( { ${svc}; } 2>&1 )
status="$?"
if [[ "${status}" -eq 0 ]]; then
[[ -t 1 ]] && echo -e "${OVER} ${TICK} ${str}"
else
[[ ! -t 1 ]] && local OVER=""
echo -e "${OVER} ${CROSS} ${output}"
fi
# Send signal to FTL to have it re-parse the gravity files
killall -s SIGHUP pihole-FTL
}
piholeEnable() {
if [[ "${2}" == "-h" ]] || [[ "${2}" == "--help" ]]; then
echo "Usage: pihole disable [time]
Example: 'pihole disable', or 'pihole disable 5m'
Disable Pi-hole subsystems
Time:
#s Disable Pi-hole functionality for # second(s)
#m Disable Pi-hole functionality for # minute(s)"
exit 0
elif [[ "${1}" == "0" ]]; then
# Disable Pi-hole
sed -i 's/^addn-hosts=\/etc\/pihole\/gravity.list/#addn-hosts=\/etc\/pihole\/gravity.list/' /etc/dnsmasq.d/01-pihole.conf
sed -i 's/^addn-hosts=\/etc\/pihole\/black.list/#addn-hosts=\/etc\/pihole\/black.list/' /etc/dnsmasq.d/01-pihole.conf
if [[ -e "$wildcardlist" ]]; then
mv "$wildcardlist" "/etc/pihole/wildcard.list"
fi
if [[ $# > 1 ]]; then
local error=false
if [[ "${2}" == *"s" ]]; then
tt=${2%"s"}
if [[ "${tt}" =~ ^-?[0-9]+$ ]];then
local str="Disabling blocking for ${tt} seconds"
echo -e " ${INFO} ${str}..."
local str="Blocking will be re-enabled in ${tt} seconds"
nohup bash -c "sleep ${tt}; pihole enable" </dev/null &>/dev/null &
else
local error=true
fi
elif [[ "${2}" == *"m" ]]; then
tt=${2%"m"}
if [[ "${tt}" =~ ^-?[0-9]+$ ]];then
local str="Disabling blocking for ${tt} minutes"
echo -e " ${INFO} ${str}..."
local str="Blocking will be re-enabled in ${tt} minutes"
tt=$((${tt}*60))
nohup bash -c "sleep ${tt}; pihole enable" </dev/null &>/dev/null &
else
local error=true
fi
elif [[ -n "${2}" ]]; then
local error=true
else
echo -e " ${INFO} Disabling blocking"
fi
if [[ ${error} == true ]];then
echo -e " ${COL_LIGHT_RED}Unknown format for delayed reactivation of the blocking!${COL_NC}"
echo -e " Try 'pihole disable --help' for more information."
exit 1
fi
local str="Pi-hole Disabled"
fi
else
# Enable Pi-hole
echo -e " ${INFO} Enabling blocking"
local str="Pi-hole Enabled"
sed -i 's/^#addn-hosts/addn-hosts/' /etc/dnsmasq.d/01-pihole.conf
if [[ -e "/etc/pihole/wildcard.list" ]]; then
mv "/etc/pihole/wildcard.list" "$wildcardlist"
fi
fi
restartDNS
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.log
off Disable the Pi-hole log at /var/log/pihole.log"
exit 0
elif [[ "${1}" == "off" ]]; then
# Disable logging
sed -i 's/^log-queries/#log-queries/' /etc/dnsmasq.d/01-pihole.conf
sed -i 's/^QUERY_LOGGING=true/QUERY_LOGGING=false/' /etc/pihole/setupVars.conf
pihole -f
echo -e " ${INFO} Disabling logging..."
local str="Logging has been disabled!"
elif [[ "${1}" == "on" ]]; then
# Enable logging
sed -i 's/^#log-queries/log-queries/' /etc/dnsmasq.d/01-pihole.conf
sed -i 's/^QUERY_LOGGING=false/QUERY_LOGGING=true/' /etc/pihole/setupVars.conf
echo -e " ${INFO} Enabling logging..."
local str="Logging has been enabled!"
else
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}
Try 'pihole logging --help' for more information."
exit 1
fi
restartDNS
echo -e "${OVER} ${TICK} ${str}"
}
statusFunc() {
local addnConfigs
# Determine if service is running on port 53 (Cr: https://superuser.com/a/806331)
if (echo > /dev/tcp/localhost/53) >/dev/null 2>&1; then
if [[ "${1}" != "web" ]]; then
echo -e " ${TICK} DNS service is running"
fi
else
case "${1}" in
"web") echo "-1";;
*) echo -e " ${CROSS} DNS service is NOT running";;
esac
return 0
fi
# Determine if Pi-hole's addn-hosts configs are commented out
addnConfigs=$(grep -i "addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf)
if [[ "${addnConfigs}" =~ "#" ]]; then
# A config is commented out
case "${1}" in
"web") echo 0;;
*) echo -e " ${CROSS} Pi-hole blocking is Disabled";;
esac
elif [[ -n "${addnConfigs}" ]]; then
# Configs are set
case "${1}" in
"web") echo 1;;
*) echo -e " ${TICK} Pi-hole blocking is Enabled";;
esac
else
# No configs were found
case "${1}" in
"web") echo 99;;
*) echo -e " ${INFO} No hosts file linked to dnsmasq, adding it in enabled state";;
esac
# Add addn-host= to dnsmasq
echo "addn-hosts=/etc/pihole/gravity.list" >> /etc/dnsmasq.d/01-pihole.conf
restartDNS
fi
}
tailFunc() {
echo -e " ${INFO} Press Ctrl-C to exit"
# Retrieve IPv4/6 addresses
source /etc/pihole/setupVars.conf
# Strip date from each line
# Colour blocklist/blacklist/wildcard entries as red
# Colour A/AAAA/DHCP strings as white
# Colour everything else as gray
tail -f /var/log/pihole.log | sed -E \
-e "s,($(date +'%b %d ')| dnsmasq[.*[0-9]]),,g" \
-e "s,(.*(gravity.list|black.list| config ).* is (${IPV4_ADDRESS%/*}|${IPV6_ADDRESS:-NULL}).*),${COL_RED}&${COL_NC}," \
-e "s,.*(query\\[A|DHCP).*,${COL_NC}&${COL_NC}," \
-e "s,.*,${COL_GRAY}&${COL_NC},"
exit 0
}
piholeCheckoutFunc() {
if [[ "$2" == "-h" ]] || [[ "$2" == "--help" ]]; then
echo "Usage: pihole checkout [repo] [branch]
Example: 'pihole checkout master' or 'pihole checkout core dev'
Switch Pi-hole subsystems to a different Github branch
Repositories:
core [branch] Change the branch of Pi-hole's core subsystem
web [branch] Change the branch of Admin Console subsystem
ftl [branch] Change the branch of Pi-hole's FTL subsystem
Branches:
master Update subsystems to the latest stable release
dev Update subsystems to the latest development release"
exit 0
fi
source "${PI_HOLE_SCRIPT_DIR}"/piholeCheckout.sh
shift
checkout "$@"
}
tricorderFunc() {
if [[ ! -p "/dev/stdin" ]]; then
echo -e " ${INFO} Please do not call Tricorder directly"
exit 1
fi
if ! (echo > /dev/tcp/tricorder.pi-hole.net/9998) >/dev/null 2>&1; then
echo -e " ${CROSS} Unable to connect to Pi-hole's Tricorder server"
exit 1
fi
if command -v openssl &> /dev/null; then
openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin
exit "$?"
else
echo -e " ${INFO} ${COL_YELLOW}Security Notice${COL_NC}: ${COL_WHITE}openssl${COL_NC} is not installed
Your debug log will be transmitted unencrypted via plain-text
There is a possibility that this could be intercepted by a third party
If you wish to cancel, press Ctrl-C to exit within 10 seconds"
secs="10"
while [[ "$secs" -gt "0" ]]; do
echo -ne "."
sleep 1
: $((secs--))
done
echo " "
nc tricorder.pi-hole.net 9999 < /dev/stdin
exit "$?"
fi
}
updateCheckFunc() {
"${PI_HOLE_SCRIPT_DIR}"/updatecheck.sh "$@"
exit 0
}
helpFunc() {
echo "Usage: pihole [options]
Example: 'pihole -w -h'
Add '-h' after specific commands for more information on usage
Whitelist/Blacklist Options:
-w, whitelist Whitelist domain(s)
-b, blacklist Blacklist domain(s)
-wild, wildcard Blacklist domain(s), and all its subdomains
Add '-h' for more info on whitelist/blacklist usage
Debugging Options:
-d, debug Start a debugging session
Add '-a' to enable automated debugging
-f, flush Flush the Pi-hole log
-r, reconfigure Reconfigure or Repair Pi-hole subsystems
-t, tail View the live output of the Pi-hole log
Options:
-a, admin Admin Console options
Add '-h' for more info on admin console usage
-c, chronometer Calculates stats and displays to an LCD
Add '-h' for more info on chronometer usage
-g, updateGravity Update the list of ad-serving domains
-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
-v, version Show installed versions of Pi-hole, Admin Console & FTL
Add '-h' for more info on version usage
uninstall Uninstall Pi-hole from your system
status Display the running status of Pi-hole subsystems
enable Enable Pi-hole subsystems
disable Disable Pi-hole subsystems
Add '-h' for more info on disable usage
restartdns Restart Pi-hole subsystems
checkout Switch Pi-hole subsystems to a different Github branch
Add '-h' for more info on checkout usage";
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
helpFunc
fi
# Handle redirecting to specific functions based on arguments
case "${1}" in
"-w" | "whitelist" ) whitelistFunc "$@";;
"-b" | "blacklist" ) blacklistFunc "$@";;
"-wild" | "wildcard" ) wildcardFunc "$@";;
"-d" | "debug" ) debugFunc "$@";;
"-f" | "flush" ) flushFunc "$@";;
"-up" | "updatePihole" ) updatePiholeFunc;;
"-r" | "reconfigure" ) reconfigurePiholeFunc;;
"-g" | "updateGravity" ) updateGravityFunc "$@";;
"-c" | "chronometer" ) chronometerFunc "$@";;
"-h" | "help" ) helpFunc;;
"-v" | "version" ) versionFunc "$@";;
"-q" | "query" ) queryFunc "$@";;
"-l" | "logging" ) piholeLogging "$@";;
"uninstall" ) uninstallFunc;;
"enable" ) piholeEnable 1;;
"disable" ) piholeEnable 0 "$2";;
"status" ) statusFunc "$2";;
"restartdns" ) restartDNS "$2";;
"-a" | "admin" ) webpageFunc "$@";;
"-t" | "tail" ) tailFunc;;
"checkout" ) piholeCheckoutFunc "$@";;
"tricorder" ) tricorderFunc;;
"updatechecker" ) updateCheckFunc "$@";;
* ) 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,5 +0,0 @@
docker-compose
pytest
pytest-xdist
pytest-cov
testinfra

View File

View File

@@ -1,16 +0,0 @@
FROM centos:7
ENV GITDIR /etc/.pihole
ENV SCRIPTDIR /opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
RUN true && \
chmod +x $SCRIPTDIR/*
ENV PH_TEST true
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -1,61 +0,0 @@
import pytest
import testinfra
check_output = testinfra.get_backend(
"local://"
).get_module("Command").check_output
@pytest.fixture
def Pihole(Docker):
''' used to contain some script stubbing, now pretty much an alias.
Also provides bash as the default run function shell '''
def run_bash(self, command, *args, **kwargs):
cmd = self.get_command(command, *args)
if self.user is not None:
out = self.run_local(
"docker exec -u %s %s /bin/bash -c %s",
self.user, self.name, cmd)
else:
out = self.run_local(
"docker exec %s /bin/bash -c %s", self.name, cmd)
out.command = self.encode(cmd)
return out
funcType = type(Docker.run)
Docker.run = funcType(run_bash, Docker, testinfra.backend.docker.DockerBackend)
return Docker
@pytest.fixture
def Docker(request, args, image, cmd):
''' combine our fixtures into a docker run command and setup finalizer to cleanup '''
assert 'docker' in check_output('id'), "Are you in the docker group?"
docker_run = "docker run {} {} {}".format(args, image, cmd)
docker_id = check_output(docker_run)
def teardown():
check_output("docker rm -f %s", docker_id)
request.addfinalizer(teardown)
docker_container = testinfra.get_backend("docker://" + docker_id)
docker_container.id = docker_id
return docker_container
@pytest.fixture
def args(request):
''' -t became required when tput began being used '''
return '-t -d'
@pytest.fixture(params=['debian', 'centos'])
def tag(request):
''' consumed by image to make the test matrix '''
return request.param
@pytest.fixture()
def image(request, tag):
''' built by test_000_build_containers.py '''
return 'pytest_pihole:{}'.format(tag)
@pytest.fixture()
def cmd(request):
''' default to doing nothing by tailing null, but don't exit '''
return 'tail -f /dev/null'

View File

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

View File

@@ -1,18 +0,0 @@
''' This file starts with 000 to make it run first '''
import pytest
import testinfra
run_local = testinfra.get_backend(
"local://"
).get_module("Command").run
@pytest.mark.parametrize("image,tag", [
( 'test/debian.Dockerfile', 'pytest_pihole:debian' ),
( 'test/centos.Dockerfile', 'pytest_pihole:centos' ),
])
def test_build_pihole_image(image, tag):
build_cmd = run_local('docker build -f {} -t {} .'.format(image, tag))
if build_cmd.rc != 0:
print build_cmd.stdout
print build_cmd.stderr
assert build_cmd.rc == 0

View File

@@ -1,438 +0,0 @@
import pytest
from textwrap import dedent
SETUPVARS = {
'PIHOLE_INTERFACE' : 'eth99',
'IPV4_ADDRESS' : '1.1.1.1',
'IPV6_ADDRESS' : 'FE80::240:D0FF:FE48:4672',
'PIHOLE_DNS_1' : '4.2.2.1',
'PIHOLE_DNS_2' : '4.2.2.2'
}
tick_box="[\x1b[1;32m\xe2\x9c\x93\x1b[0m]".decode("utf-8")
cross_box="[\x1b[1;31m\xe2\x9c\x97\x1b[0m]".decode("utf-8")
info_box="[i]".decode("utf-8")
def test_setupVars_are_sourced_to_global_scope(Pihole):
''' currently update_dialogs sources setupVars with a dot,
then various other functions use the variables.
This confirms the sourced variables are in scope between functions '''
setup_var_file = 'cat <<EOF> /etc/pihole/setupVars.conf\n'
for k,v in SETUPVARS.iteritems():
setup_var_file += "{}={}\n".format(k, v)
setup_var_file += "EOF\n"
Pihole.run(setup_var_file)
script = dedent('''\
set -e
printSetupVars() {
# Currently debug test function only
echo "Outputting sourced variables"
echo "PIHOLE_INTERFACE=${PIHOLE_INTERFACE}"
echo "IPV4_ADDRESS=${IPV4_ADDRESS}"
echo "IPV6_ADDRESS=${IPV6_ADDRESS}"
echo "PIHOLE_DNS_1=${PIHOLE_DNS_1}"
echo "PIHOLE_DNS_2=${PIHOLE_DNS_2}"
}
update_dialogs() {
. /etc/pihole/setupVars.conf
}
update_dialogs
printSetupVars
''')
output = run_script(Pihole, script).stdout
for k,v in SETUPVARS.iteritems():
assert "{}={}".format(k, v) in output
def test_setupVars_saved_to_file(Pihole):
''' confirm saved settings are written to a file for future updates to re-use '''
set_setup_vars = '\n' # dedent works better with this and padding matching script below
for k,v in SETUPVARS.iteritems():
set_setup_vars += " {}={}\n".format(k, v)
Pihole.run(set_setup_vars).stdout
script = dedent('''\
set -e
echo start
TERM=xterm
source /opt/pihole/basic-install.sh
{}
mkdir -p /etc/dnsmasq.d
version_check_dnsmasq
finalExports
cat /etc/pihole/setupVars.conf
'''.format(set_setup_vars))
output = run_script(Pihole, script).stdout
for k,v in SETUPVARS.iteritems():
assert "{}={}".format(k, v) in output
def test_configureFirewall_firewalld_running_no_errors(Pihole):
''' confirms firewalld rules are applied when firewallD is running '''
# firewallD returns 'running' as status
mock_command('firewall-cmd', {'*':('running', 0)}, Pihole)
# Whiptail dialog returns Ok for user prompt
mock_command('whiptail', {'*':('', 0)}, Pihole)
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'Configuring FirewallD for httpd and dnsmasq'
assert expected_stdout in configureFirewall.stdout
firewall_calls = Pihole.run('cat /var/log/firewall-cmd').stdout
assert 'firewall-cmd --state' in firewall_calls
assert 'firewall-cmd --permanent --add-service=http --add-service=dns' in firewall_calls
assert 'firewall-cmd --reload' in firewall_calls
def test_configureFirewall_firewalld_disabled_no_errors(Pihole):
''' confirms firewalld rules are not applied when firewallD is not running '''
# firewallD returns non-running status
mock_command('firewall-cmd', {'*':('not running', '1')}, Pihole)
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'No active firewall detected.. skipping firewall configuration'
assert expected_stdout in configureFirewall.stdout
def test_configureFirewall_firewalld_enabled_declined_no_errors(Pihole):
''' confirms firewalld rules are not applied when firewallD is running, user declines ruleset '''
# firewallD returns running status
mock_command('firewall-cmd', {'*':('running', 0)}, Pihole)
# Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*':('', 1)}, Pihole)
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'Not installing firewall rulesets.'
assert expected_stdout in configureFirewall.stdout
def test_configureFirewall_no_firewall(Pihole):
''' confirms firewall skipped no daemon is running '''
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'No active firewall detected'
assert expected_stdout in configureFirewall.stdout
def test_configureFirewall_IPTables_enabled_declined_no_errors(Pihole):
''' confirms IPTables rules are not applied when IPTables is running, user declines ruleset '''
# iptables command exists
mock_command('iptables', {'*':('', '0')}, Pihole)
# modinfo returns always true (ip_tables module check)
mock_command('modinfo', {'*':('', '0')}, Pihole)
# Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*':('', '1')}, Pihole)
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'Not installing firewall rulesets.'
assert expected_stdout in configureFirewall.stdout
def test_configureFirewall_IPTables_enabled_rules_exist_no_errors(Pihole):
''' confirms IPTables rules are not applied when IPTables is running and rules exist '''
# iptables command exists and returns 0 on calls (should return 0 on iptables -C)
mock_command('iptables', {'-S':('-P INPUT DENY', '0')}, Pihole)
# modinfo returns always true (ip_tables module check)
mock_command('modinfo', {'*':('', '0')}, Pihole)
# Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*':('', '0')}, Pihole)
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'Installing new IPTables firewall rulesets'
assert expected_stdout in configureFirewall.stdout
firewall_calls = Pihole.run('cat /var/log/iptables').stdout
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT' not in firewall_calls
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT' not in firewall_calls
assert 'iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT' not in firewall_calls
def test_configureFirewall_IPTables_enabled_not_exist_no_errors(Pihole):
''' confirms IPTables rules are applied when IPTables is running and rules do not exist '''
# iptables command and returns 0 on calls (should return 1 on iptables -C)
mock_command('iptables', {'-S':('-P INPUT DENY', '0'), '-C':('', 1), '-I':('', 0)}, Pihole)
# modinfo returns always true (ip_tables module check)
mock_command('modinfo', {'*':('', '0')}, Pihole)
# Whiptail dialog returns Cancel for user prompt
mock_command('whiptail', {'*':('', '0')}, Pihole)
configureFirewall = Pihole.run('''
source /opt/pihole/basic-install.sh
configureFirewall
''')
expected_stdout = 'Installing new IPTables firewall rulesets'
assert expected_stdout in configureFirewall.stdout
firewall_calls = Pihole.run('cat /var/log/iptables').stdout
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT' in firewall_calls
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT' in firewall_calls
assert 'iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT' in firewall_calls
def test_installPiholeWeb_fresh_install_no_errors(Pihole):
''' confirms all web page assets from Core repo are installed on a fresh build '''
installWeb = Pihole.run('''
source /opt/pihole/basic-install.sh
installPiholeWeb
''')
assert info_box + ' Installing blocking page...' in installWeb.stdout
assert tick_box + ' Creating directory for blocking page, and copying files' in installWeb.stdout
assert cross_box + ' Backing up index.lighttpd.html' in installWeb.stdout
assert 'No default index.lighttpd.html file found... not backing up' in installWeb.stdout
assert tick_box + ' Installing sudoer file' in installWeb.stdout
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
assert 'index.php' in web_directory
assert 'blockingpage.css' in web_directory
def test_update_package_cache_success_no_errors(Pihole):
''' confirms package cache was updated without any errors'''
updateCache = Pihole.run('''
source /opt/pihole/basic-install.sh
distro_check
update_package_cache
''')
assert tick_box + ' Update local cache of available packages' in updateCache.stdout
assert 'Error: Unable to update package cache.' not in updateCache.stdout
def test_update_package_cache_failure_no_errors(Pihole):
''' confirms package cache was not updated'''
mock_command('apt-get', {'update':('', '1')}, Pihole)
updateCache = Pihole.run('''
source /opt/pihole/basic-install.sh
distro_check
update_package_cache
''')
assert cross_box + ' Update local cache of available packages' in updateCache.stdout
assert 'Error: Unable to update package cache.' in updateCache.stdout
def test_FTL_detect_aarch64_no_errors(Pihole):
''' confirms only aarch64 package is downloaded for FTL engine '''
# mock uname to return aarch64 platform
mock_command('uname', {'-m':('aarch64', '0')}, Pihole)
# mock ldd to respond with aarch64 shared library
mock_command('ldd', {'/bin/ls':('/lib/ld-linux-aarch64.so.1', '0')}, Pihole)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
FTLdetect
''')
expected_stdout = info_box + ' FTL Checks...'
assert expected_stdout in detectPlatform.stdout
expected_stdout = tick_box + ' Detected ARM-aarch64 architecture'
assert expected_stdout in detectPlatform.stdout
expected_stdout = tick_box + ' Downloading and Installing FTL'
assert expected_stdout in detectPlatform.stdout
def test_FTL_detect_armv6l_no_errors(Pihole):
''' confirms only armv6l package is downloaded for FTL engine '''
# mock uname to return armv6l platform
mock_command('uname', {'-m':('armv6l', '0')}, Pihole)
# mock ldd to respond with aarch64 shared library
mock_command('ldd', {'/bin/ls':('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
FTLdetect
''')
expected_stdout = info_box + ' FTL Checks...'
assert expected_stdout in detectPlatform.stdout
expected_stdout = tick_box + ' Detected ARM-hf architecture (armv6 or lower)'
assert expected_stdout in detectPlatform.stdout
expected_stdout = tick_box + ' Downloading and Installing FTL'
assert expected_stdout in detectPlatform.stdout
def test_FTL_detect_armv7l_no_errors(Pihole):
''' confirms only armv7l package is downloaded for FTL engine '''
# mock uname to return armv7l platform
mock_command('uname', {'-m':('armv7l', '0')}, Pihole)
# mock ldd to respond with aarch64 shared library
mock_command('ldd', {'/bin/ls':('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
FTLdetect
''')
expected_stdout = info_box + ' FTL Checks...'
assert expected_stdout in detectPlatform.stdout
expected_stdout = tick_box + ' Detected ARM-hf architecture (armv7+)'
assert expected_stdout in detectPlatform.stdout
expected_stdout = tick_box + ' Downloading and Installing FTL'
assert expected_stdout in detectPlatform.stdout
def test_FTL_detect_x86_64_no_errors(Pihole):
''' confirms only x86_64 package is downloaded for FTL engine '''
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
FTLdetect
''')
expected_stdout = info_box + ' FTL Checks...'
assert expected_stdout in detectPlatform.stdout
expected_stdout = tick_box + ' Detected x86_64 architecture'
assert expected_stdout in detectPlatform.stdout
expected_stdout = tick_box + ' Downloading and Installing FTL'
assert expected_stdout in detectPlatform.stdout
def test_FTL_detect_unknown_no_errors(Pihole):
''' confirms only generic package is downloaded for FTL engine '''
# mock uname to return generic platform
mock_command('uname', {'-m':('mips', '0')}, Pihole)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
FTLdetect
''')
expected_stdout = 'Not able to detect architecture (unknown: mips)'
assert expected_stdout in detectPlatform.stdout
def test_FTL_download_aarch64_no_errors(Pihole):
''' confirms only aarch64 package is downloaded for FTL engine '''
# mock uname to return generic platform
download_binary = Pihole.run('''
source /opt/pihole/basic-install.sh
FTLinstall pihole-FTL-aarch64-linux-gnu
''')
expected_stdout = tick_box + ' Downloading and Installing FTL'
assert expected_stdout in download_binary.stdout
error = 'Error: Download of binary from Github failed'
assert error not in download_binary.stdout
error = 'Error: URL not found'
assert error not in download_binary.stdout
def test_FTL_download_unknown_fails_no_errors(Pihole):
''' confirms unknown binary is not downloaded for FTL engine '''
# mock uname to return generic platform
download_binary = Pihole.run('''
source /opt/pihole/basic-install.sh
FTLinstall pihole-FTL-mips
''')
expected_stdout = cross_box + ' Downloading and Installing FTL'
assert expected_stdout in download_binary.stdout
error = 'Error: URL not found'
assert error in download_binary.stdout
def test_FTL_binary_installed_and_responsive_no_errors(Pihole):
''' confirms FTL binary is copied and functional in installed location '''
installed_binary = Pihole.run('''
source /opt/pihole/basic-install.sh
FTLdetect
pihole-FTL version
''')
expected_stdout = 'v'
assert expected_stdout in installed_binary.stdout
# def test_FTL_support_files_installed(Pihole):
# ''' confirms FTL support files are installed '''
# support_files = Pihole.run('''
# source /opt/pihole/basic-install.sh
# FTLdetect
# stat -c '%a %n' /var/log/pihole-FTL.log
# stat -c '%a %n' /run/pihole-FTL.port
# stat -c '%a %n' /run/pihole-FTL.pid
# ls -lac /run
# ''')
# assert '644 /run/pihole-FTL.port' in support_files.stdout
# assert '644 /run/pihole-FTL.pid' in support_files.stdout
# assert '644 /var/log/pihole-FTL.log' in support_files.stdout
def test_IPv6_only_link_local(Pihole):
''' confirms IPv6 blocking is disabled for Link-local address '''
# mock ip -6 address to return Link-local address
mock_command_2('ip', {'-6 address':('inet6 fe80::d210:52fa:fe00:7ad7/64 scope link', '0')}, Pihole)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
useIPv6dialog
''')
expected_stdout = 'Unable to find IPv6 ULA/GUA address, IPv6 adblocking will not be enabled'
assert expected_stdout in detectPlatform.stdout
def test_IPv6_only_ULA(Pihole):
''' confirms IPv6 blocking is enabled for ULA addresses '''
# mock ip -6 address to return ULA address
mock_command_2('ip', {'-6 address':('inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
useIPv6dialog
''')
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
assert expected_stdout in detectPlatform.stdout
def test_IPv6_only_GUA(Pihole):
''' confirms IPv6 blocking is enabled for GUA addresses '''
# mock ip -6 address to return GUA address
mock_command_2('ip', {'-6 address':('inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
useIPv6dialog
''')
expected_stdout = 'Found IPv6 GUA address, using it for blocking IPv6 ads'
assert expected_stdout in detectPlatform.stdout
def test_IPv6_GUA_ULA_test(Pihole):
''' confirms IPv6 blocking is enabled for GUA and ULA addresses '''
# mock ip -6 address to return GUA and ULA addresses
mock_command_2('ip', {'-6 address':('inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global\ninet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
useIPv6dialog
''')
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
assert expected_stdout in detectPlatform.stdout
def test_IPv6_ULA_GUA_test(Pihole):
''' confirms IPv6 blocking is enabled for GUA and ULA addresses '''
# mock ip -6 address to return ULA and GUA addresses
mock_command_2('ip', {'-6 address':('inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global\ninet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole)
detectPlatform = Pihole.run('''
source /opt/pihole/basic-install.sh
useIPv6dialog
''')
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
assert expected_stdout in detectPlatform.stdout
# Helper functions
def mock_command(script, args, container):
''' Allows for setup of commands we don't really want to have to run for real in unit tests '''
full_script_path = '/usr/local/bin/{}'.format(script)
mock_script = dedent('''\
#!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script}
case "\$1" in'''.format(script=script))
for k, v in args.iteritems():
case = dedent('''
{arg})
echo {res}
exit {retcode}
;;'''.format(arg=k, res=v[0], retcode=v[1]))
mock_script += case
mock_script += dedent('''
esac''')
container.run('''
cat <<EOF> {script}\n{content}\nEOF
chmod +x {script}
rm -f /var/log/{scriptlog}'''.format(script=full_script_path, content=mock_script, scriptlog=script))
def mock_command_2(script, args, container):
''' Allows for setup of commands we don't really want to have to run for real in unit tests '''
full_script_path = '/usr/local/bin/{}'.format(script)
mock_script = dedent('''\
#!/bin/bash -e
echo "\$0 \$@" >> /var/log/{script}
case "\$1 \$2" in'''.format(script=script))
for k, v in args.iteritems():
case = dedent('''
\"{arg}\")
echo \"{res}\"
exit {retcode}
;;'''.format(arg=k, res=v[0], retcode=v[1]))
mock_script += case
mock_script += dedent('''
esac''')
container.run('''
cat <<EOF> {script}\n{content}\nEOF
chmod +x {script}
rm -f /var/log/{scriptlog}'''.format(script=full_script_path, content=mock_script, scriptlog=script))
def run_script(Pihole, script):
result = Pihole.run(script)
assert result.rc == 0
return result

View File

@@ -1,13 +0,0 @@
import pytest
import testinfra
run_local = testinfra.get_backend(
"local://"
).get_module("Command").run
def test_scripts_pass_shellcheck():
''' Make sure shellcheck does not find anything wrong with our shell scripts '''
shellcheck = "find . -type f -name 'update.sh' | while read file; do shellcheck -x \"$file\" -e SC1090,SC1091; done;"
results = run_local(shellcheck)
print results.stdout
assert '' == results.stdout