mirror of
https://github.com/pi-hole/pi-hole.git
synced 2024-12-25 06:10:20 +00:00
commit
ddbdb51d20
45 changed files with 6495 additions and 4889 deletions
|
@ -9,7 +9,7 @@ end_of_line = lf
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = tab
|
indent_size = tab
|
||||||
tab_width = 2
|
tab_width = 4
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
|
2
.github/dco.yml
vendored
Normal file
2
.github/dco.yml
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
require:
|
||||||
|
members: false
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -3,6 +3,11 @@
|
||||||
*.swp
|
*.swp
|
||||||
__pycache__
|
__pycache__
|
||||||
.cache
|
.cache
|
||||||
|
.pytest_cache
|
||||||
|
.tox
|
||||||
|
.eggs
|
||||||
|
*.egg-info
|
||||||
|
|
||||||
|
|
||||||
# Created by https://www.gitignore.io/api/jetbrains+iml
|
# Created by https://www.gitignore.io/api/jetbrains+iml
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
<option name="OTHER_INDENT_OPTIONS">
|
|
||||||
<value>
|
|
||||||
<option name="INDENT_SIZE" value="2" />
|
|
||||||
<option name="TAB_SIZE" value="2" />
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<MarkdownNavigatorCodeStyleSettings>
|
<MarkdownNavigatorCodeStyleSettings>
|
||||||
<option name="RIGHT_MARGIN" value="72" />
|
<option name="RIGHT_MARGIN" value="72" />
|
||||||
</MarkdownNavigatorCodeStyleSettings>
|
</MarkdownNavigatorCodeStyleSettings>
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
linters:
|
linters:
|
||||||
shellcheck:
|
shellcheck:
|
||||||
shell: bash
|
shell: bash
|
||||||
|
phpcs:
|
||||||
|
csslint:
|
||||||
|
flake8:
|
||||||
|
|
|
@ -7,4 +7,6 @@ python:
|
||||||
install:
|
install:
|
||||||
- pip install -r requirements.txt
|
- pip install -r requirements.txt
|
||||||
|
|
||||||
script: py.test -vv
|
script:
|
||||||
|
# tox.ini handles setup, ordering of docker build first, and then run tests
|
||||||
|
- tox
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
_This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._
|
|
||||||
|
|
||||||
# Contributors Guide
|
# Contributors Guide
|
||||||
|
|
||||||
Please read and understand the contribution guide before creating an issue or pull request.
|
Please read and understand the contribution guide before creating an issue or pull request.
|
||||||
|
|
71
README.md
71
README.md
|
@ -3,7 +3,7 @@
|
||||||
<b>Network-wide ad blocking via your own Linux hardware</b><br/>
|
<b>Network-wide ad blocking via your own Linux hardware</b><br/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
The Pi-hole is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content, without installing any client-side software.
|
The Pi-hole[®](https://pi-hole.net/trademark-rules-and-brand-guidelines/) is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content, without installing any client-side software.
|
||||||
|
|
||||||
- **Easy-to-install**: our versatile installer walks you through the process, and [takes less than ten minutes](https://www.youtube.com/watch?v=vKWjx1AQYgs)
|
- **Easy-to-install**: our 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
|
- **Resolute**: content is blocked in _non-browser locations_, such as ad-laden mobile apps and smart TVs
|
||||||
|
@ -27,7 +27,7 @@ Those who want to get started quickly and conveniently, may install Pi-hole usin
|
||||||
#### `curl -sSL https://install.pi-hole.net | bash`
|
#### `curl -sSL https://install.pi-hole.net | bash`
|
||||||
|
|
||||||
## Alternative Install Methods
|
## Alternative Install Methods
|
||||||
[Piping to `bash` is controversial](https://pi-hole.net/2016/07/25/curling-and-piping-to-bash), as it prevents you from [reading code that is about to run](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) on your system. Therefore, we provide these alternative installation methods which allow code review before installation:
|
[Piping to `bash` is controversial](https://pi-hole.net/2016/07/25/curling-and-piping-to-bash), as it prevents you from [reading code that is about to run](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) on your system. Therefore, we provide these alternative installation methods which allow code review before installation:
|
||||||
|
|
||||||
### Method 1: Clone our repository and run
|
### Method 1: Clone our repository and run
|
||||||
```
|
```
|
||||||
|
@ -60,16 +60,21 @@ Make no mistake: **your support is absolutely vital to help keep us innovating!*
|
||||||
### Donations
|
### Donations
|
||||||
Sending a donation using our links below is **extremely helpful** in offsetting a portion of our monthly expenses:
|
Sending a donation using our links below is **extremely helpful** in offsetting a portion of our monthly expenses:
|
||||||
|
|
||||||
<img src="https://pi-hole.github.io/graphics/Badges/paypal-badge-black.svg" width="24" height="24" alt="PP"/> <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY">Donate via PayPal</a><br/>
|
- <img src="https://pi-hole.github.io/graphics/Badges/paypal-badge-black.svg" width="24" height="24" alt="PP"/> <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY">Donate via PayPal</a><br/>
|
||||||
<img src="https://pi-hole.github.io/graphics/Badges/bitcoin-badge-black.svg" width="24" height="24" alt="BTC"/> Bitcoin Address: <code>1GKnevUnVaQM2pQieMyeHkpr8DXfkpfAtL</code>
|
- <img src="https://pi-hole.github.io/graphics/Badges/bitcoin-badge-black.svg" width="24" height="24" alt="BTC"/> [Bitcoin](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763): <code>
|
||||||
|
3MDPzjXu2hjw5sGLJvKUi1uXbvQPzVrbpF</code></br>
|
||||||
|
- <img src="https://pi-hole.github.io/graphics/Badges/bitcoin-badge-black.svg" width="24" height="24" alt="BTC"/> [Bitcoin Cash](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763): <code>qzqsz4aju2eecc6uhs7tus4vlwhhela24sdruf4qp5</code></br>
|
||||||
|
- <img src="https://pi-hole.github.io/graphics/Badges/ethereum-badge-black.svg" width="24" height="24" alt="BTC"/> [Ethereum](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763): <code>0x79d4e90A4a0C732819526c93e21A3F1356A2FAe1</code>
|
||||||
|
|
||||||
### Alternative support
|
### Alternative support
|
||||||
If you'd rather not donate (_which is okay!_), there are other ways you can help support us:
|
If you'd rather not [donate](https://pi-hole.net/donate/) (_which is okay!_), there are other ways you can help support us:
|
||||||
|
- [Patreon](https://patreon.com/pihole) _Become a patron for rewards_
|
||||||
- [Digital Ocean](http://www.digitalocean.com/?refcode=344d234950e1) affiliate link
|
- [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) _save $5 when you spend $9 using our affiliate link_
|
||||||
- [UNIXstickers.com](http://unixstickers.refr.cc/jacobs) affiliate link
|
- [Pi-hole Swag Store](https://pi-hole.net/shop/) _affiliate link_
|
||||||
- [Pi-hole Swag Store](https://pi-hole.net/shop/)
|
- [Amazon](http://www.amazon.com/exec/obidos/redirect-home/pihole09-20) _affiliate link_
|
||||||
|
- [DNS Made Easy](https://cp.dnsmadeeasy.com/u/133706) _affiliate link_
|
||||||
|
- [Vultr](http://www.vultr.com/?ref=7190426) _affiliate link_
|
||||||
- Spreading the word about our software, and how you have benefited from it
|
- Spreading the word about our software, and how you have benefited from it
|
||||||
|
|
||||||
### Contributing via GitHub
|
### Contributing via GitHub
|
||||||
|
@ -93,9 +98,6 @@ While we are primarily reachable on our <a href="https://discourse.pi-hole.net/"
|
||||||
<li><a href="https://discourse.pi-hole.net/c/faqs">Frequently Asked Questions</a></li>
|
<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://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>
|
<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://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://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://gitter.im/pi-hole/pi-hole">Gitter</a> (Real-time chat)</li>
|
||||||
|
@ -127,7 +129,7 @@ You can read our [Core Feature Breakdown](https://github.com/pi-hole/pi-hole/wik
|
||||||
### The Web Interface Dashboard
|
### The Web Interface Dashboard
|
||||||
This [optional dashboard](https://github.com/pi-hole/AdminLTE) allows you to view stats, change settings, and configure your Pi-hole. It's the power of the Command Line Interface, with none of the learning curve!
|
This [optional dashboard](https://github.com/pi-hole/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>
|
<img src="https://pi-hole.github.io/graphics/Screenshots/pihole-dashboard.png" alt="Pi-hole Dashboard"/></a>
|
||||||
|
|
||||||
Some notable features include:
|
Some notable features include:
|
||||||
* Mobile friendly interface
|
* Mobile friendly interface
|
||||||
|
@ -142,11 +144,11 @@ Some notable features include:
|
||||||
There are several ways to [access the dashboard](https://discourse.pi-hole.net/t/how-do-i-access-pi-holes-dashboard-admin-interface/3168):
|
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/`
|
1. `http://<IP_ADDPRESS_OF_YOUR_PI_HOLE>/admin/`
|
||||||
2. `http:/pi.hole/admin/` (when using Pi-hole as your DNS server)
|
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)
|
3. `http://pi.hole/` (when using Pi-hole as your DNS server)
|
||||||
|
|
||||||
## The Faster-Than-Light Engine
|
## 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*!
|
FTLDNS[™](https://pi-hole.net/trademark-rules-and-brand-guidelines/) is a lightweight, purpose-built daemon used to provide statistics needed for the Web Interface, and its API can be easily integrated into your own projects. As the name implies, FTLDNS does this all *very quickly*!
|
||||||
|
|
||||||
Some of the statistics you can integrate include:
|
Some of the statistics you can integrate include:
|
||||||
* Total number of domains being blocked
|
* Total number of domains being blocked
|
||||||
|
@ -172,31 +174,13 @@ Pi-hole being a **advertising-aware DNS/Web server**, makes use of the following
|
||||||
* [AdminLTE Dashboard](https://github.com/almasaeed2010/AdminLTE) - premium admin control panel based on Bootstrap 3.x
|
* [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.
|
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 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 Pi-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)
|
|
||||||
- [Windows DNS Swapper](https://github.com/roots84/DNS-Swapper), see [#1400](https://github.com/pi-hole/pi-hole/issues/1400)
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
## Coverage
|
## Coverage
|
||||||
|
- [Software Engineering Daily: Interview with the creator of Pi-hole](https://softwareengineeringdaily.com/2018/05/29/pi-hole-ad-blocker-hardware-with-jacob-salmela/)
|
||||||
|
- [Bloomberg Business Week: Brotherhood of the Ad blockers](https://www.bloomberg.com/news/features/2018-05-10/inside-the-brotherhood-of-pi-hole-ad-blockers)
|
||||||
|
- [Securing DNS across all of my devices with Pi-Hole + DNS-over-HTTPS + 1.1.1.1](https://scotthelme.co.uk/securing-dns-across-all-of-my-devices-with-pihole-dns-over-https-1-1-1-1/)
|
||||||
|
- [Adafruit: installing Pi-hole on a Pi Zero W](https://learn.adafruit.com/pi-hole-ad-blocker-with-pi-zero-w/install-pi-hole)
|
||||||
- [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/)
|
- [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/)
|
- [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/)
|
- [Catchpoint: Ad-Blocking on Apple iOS9: Valuing the End User Experience](http://blog.catchpoint.com/2015/09/14/ad-blocking-apple/)
|
||||||
|
@ -215,3 +199,12 @@ While quite outdated at this point, [this original blog post about Pi-hole](http
|
||||||
- [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: 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/)
|
- [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)
|
- [Know How 355: Killing ads with a Raspberry Pi-Hole!](https://www.twit.tv/shows/know-how/episodes/355)
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
## Pi-hole Projects
|
||||||
|
- [The Big Blocklist Collection](https://wally3k.github.io)
|
||||||
|
- [Pie in the Sky-Hole](https://dlaa.me/blog/post/skyhole)
|
||||||
|
- [Copernicus: Windows Tray Application](https://github.com/goldbattle/copernicus)
|
||||||
|
- [Magic Mirror with DNS Filtering](https://zonksec.com/blog/magic-mirror-dns-filtering/#dnssoftware)
|
||||||
|
- [Windows DNS Swapper](https://github.com/roots84/DNS-Swapper)
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
# 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
|
|
||||||
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
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,10 +13,11 @@ basename=pihole
|
||||||
piholeDir=/etc/"${basename}"
|
piholeDir=/etc/"${basename}"
|
||||||
whitelist="${piholeDir}"/whitelist.txt
|
whitelist="${piholeDir}"/whitelist.txt
|
||||||
blacklist="${piholeDir}"/blacklist.txt
|
blacklist="${piholeDir}"/blacklist.txt
|
||||||
readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
|
readonly regexlist="/etc/pihole/regex.list"
|
||||||
reload=false
|
reload=false
|
||||||
addmode=true
|
addmode=true
|
||||||
verbose=true
|
verbose=true
|
||||||
|
wildcard=false
|
||||||
|
|
||||||
domList=()
|
domList=()
|
||||||
|
|
||||||
|
@ -28,16 +29,19 @@ source ${colfile}
|
||||||
|
|
||||||
|
|
||||||
helpFunc() {
|
helpFunc() {
|
||||||
if [[ "${listMain}" == "${whitelist}" ]]; then
|
if [[ "${listMain}" == "${whitelist}" ]]; then
|
||||||
param="w"
|
param="w"
|
||||||
type="white"
|
type="white"
|
||||||
elif [[ "${listMain}" == "${wildcardlist}" ]]; then
|
elif [[ "${listMain}" == "${regexlist}" && "${wildcard}" == true ]]; then
|
||||||
param="wild"
|
param="-wild"
|
||||||
type="wildcard black"
|
type="wildcard black"
|
||||||
else
|
elif [[ "${listMain}" == "${regexlist}" ]]; then
|
||||||
param="b"
|
param="-regex"
|
||||||
type="black"
|
type="regex black"
|
||||||
fi
|
else
|
||||||
|
param="b"
|
||||||
|
type="black"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Usage: pihole -${param} [options] <domain> <domain2 ...>
|
echo "Usage: pihole -${param} [options] <domain> <domain2 ...>
|
||||||
Example: 'pihole -${param} site.com', or 'pihole -${param} site1.com site2.com'
|
Example: 'pihole -${param} site.com', or 'pihole -${param} site1.com site2.com'
|
||||||
|
@ -55,212 +59,216 @@ Options:
|
||||||
}
|
}
|
||||||
|
|
||||||
EscapeRegexp() {
|
EscapeRegexp() {
|
||||||
# This way we may safely insert an arbitrary
|
# This way we may safely insert an arbitrary
|
||||||
# string in our regular expressions
|
# string in our regular expressions
|
||||||
# Also remove leading "." if present
|
# This sed is intentionally executed in three steps to ease maintainability
|
||||||
echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g"
|
# The first sed removes any amount of leading dots
|
||||||
|
echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g"
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleOther() {
|
HandleOther() {
|
||||||
# Convert to lowercase
|
# Convert to lowercase
|
||||||
domain="${1,,}"
|
domain="${1,,}"
|
||||||
|
|
||||||
# Check validity of domain
|
# Check validity of domain (don't check for regex entries)
|
||||||
if [[ "${#domain}" -le 253 ]]; then
|
if [[ "${#domain}" -le 253 ]]; then
|
||||||
validDomain=$(grep -P "^((-|_)*[a-z\d]((-|_)*[a-z\d])*(-|_)*)(\.(-|_)*([a-z\d]((-|_)*[a-z\d])*))*$" <<< "${domain}") # Valid chars check
|
if [[ "${listMain}" == "${regexlist}" && "${wildcard}" == false ]]; then
|
||||||
validDomain=$(grep -P "^[^\.]{1,63}(\.[^\.]{1,63})*$" <<< "${validDomain}") # Length of each label
|
validDomain="${domain}"
|
||||||
fi
|
else
|
||||||
|
validDomain=$(grep -P "^((-|_)*[a-z\\d]((-|_)*[a-z\\d])*(-|_)*)(\\.(-|_)*([a-z\\d]((-|_)*[a-z\\d])*))*$" <<< "${domain}") # Valid chars check
|
||||||
|
validDomain=$(grep -P "^[^\\.]{1,63}(\\.[^\\.]{1,63})*$" <<< "${validDomain}") # Length of each label
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -n "${validDomain}" ]]; then
|
if [[ -n "${validDomain}" ]]; then
|
||||||
domList=("${domList[@]}" ${validDomain})
|
domList=("${domList[@]}" ${validDomain})
|
||||||
else
|
else
|
||||||
echo -e " ${CROSS} ${domain} is not a valid argument or domain name!"
|
echo -e " ${CROSS} ${domain} is not a valid argument or domain name!"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
PoplistFile() {
|
PoplistFile() {
|
||||||
# Check whitelist file exists, and if not, create it
|
# Check whitelist file exists, and if not, create it
|
||||||
if [[ ! -f "${whitelist}" ]]; then
|
if [[ ! -f "${whitelist}" ]]; then
|
||||||
touch "${whitelist}"
|
touch "${whitelist}"
|
||||||
fi
|
|
||||||
|
|
||||||
# Check blacklist file exists, and if not, create it
|
|
||||||
if [[ ! -f "${blacklist}" ]]; then
|
|
||||||
touch "${blacklist}"
|
|
||||||
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
|
fi
|
||||||
|
|
||||||
|
# Check blacklist file exists, and if not, create it
|
||||||
|
if [[ ! -f "${blacklist}" ]]; then
|
||||||
|
touch "${blacklist}"
|
||||||
|
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}"
|
||||||
|
else
|
||||||
|
RemoveDomain "${dom}" "${listMain}"
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDomain() {
|
AddDomain() {
|
||||||
list="$2"
|
list="$2"
|
||||||
domain=$(EscapeRegexp "$1")
|
domain=$(EscapeRegexp "$1")
|
||||||
|
|
||||||
[[ "${list}" == "${whitelist}" ]] && listname="whitelist"
|
[[ "${list}" == "${whitelist}" ]] && listname="whitelist"
|
||||||
[[ "${list}" == "${blacklist}" ]] && listname="blacklist"
|
[[ "${list}" == "${blacklist}" ]] && listname="blacklist"
|
||||||
[[ "${list}" == "${wildcardlist}" ]] && listname="wildcard blacklist"
|
|
||||||
|
|
||||||
if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
|
if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
|
||||||
[[ "${list}" == "${whitelist}" && -z "${type}" ]] && type="--whitelist-only"
|
[[ "${list}" == "${whitelist}" && -z "${type}" ]] && type="--whitelist-only"
|
||||||
[[ "${list}" == "${blacklist}" && -z "${type}" ]] && type="--blacklist-only"
|
[[ "${list}" == "${blacklist}" && -z "${type}" ]] && type="--blacklist-only"
|
||||||
bool=true
|
bool=true
|
||||||
# Is the domain in the list we want to add it to?
|
# Is the domain in the list we want to add it to?
|
||||||
grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
|
grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
|
||||||
|
|
||||||
if [[ "${bool}" == false ]]; then
|
if [[ "${bool}" == false ]]; then
|
||||||
# Domain not found in the whitelist file, add it!
|
# Domain not found in the whitelist file, add it!
|
||||||
if [[ "${verbose}" == true ]]; then
|
if [[ "${verbose}" == true ]]; then
|
||||||
echo -e " ${INFO} Adding $1 to $listname..."
|
echo -e " ${INFO} Adding ${1} to ${listname}..."
|
||||||
fi
|
fi
|
||||||
reload=true
|
reload=true
|
||||||
# Add it to the list we want to add it to
|
# Add it to the list we want to add it to
|
||||||
echo "$1" >> "${list}"
|
echo "$1" >> "${list}"
|
||||||
else
|
else
|
||||||
if [[ "${verbose}" == true ]]; then
|
if [[ "${verbose}" == true ]]; then
|
||||||
echo -e " ${INFO} ${1} already exists in ${listname}, no need to add!"
|
echo -e " ${INFO} ${1} already exists in ${listname}, no need to add!"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
elif [[ "${list}" == "${regexlist}" ]]; then
|
||||||
|
[[ -z "${type}" ]] && type="--wildcard-only"
|
||||||
|
bool=true
|
||||||
|
domain="${1}"
|
||||||
|
|
||||||
|
[[ "${wildcard}" == true ]] && domain="(^|\\.)${domain//\./\\.}$"
|
||||||
|
|
||||||
|
# Is the domain in the list?
|
||||||
|
# Search only for exactly matching lines
|
||||||
|
grep -Fx "${domain}" "${regexlist}" > /dev/null 2>&1 || bool=false
|
||||||
|
|
||||||
|
if [[ "${bool}" == false ]]; then
|
||||||
|
if [[ "${verbose}" == true ]]; then
|
||||||
|
echo -e " ${INFO} Adding ${domain} to regex list..."
|
||||||
|
fi
|
||||||
|
reload="restart"
|
||||||
|
echo "$domain" >> "${regexlist}"
|
||||||
|
else
|
||||||
|
if [[ "${verbose}" == true ]]; then
|
||||||
|
echo -e " ${INFO} ${domain} already exists in regex list, no need to add!"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
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() {
|
RemoveDomain() {
|
||||||
list="$2"
|
list="$2"
|
||||||
domain=$(EscapeRegexp "$1")
|
domain=$(EscapeRegexp "$1")
|
||||||
|
|
||||||
[[ "${list}" == "${whitelist}" ]] && listname="whitelist"
|
[[ "${list}" == "${whitelist}" ]] && listname="whitelist"
|
||||||
[[ "${list}" == "${blacklist}" ]] && listname="blacklist"
|
[[ "${list}" == "${blacklist}" ]] && listname="blacklist"
|
||||||
[[ "${list}" == "${wildcardlist}" ]] && listname="wildcard blacklist"
|
|
||||||
|
|
||||||
if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
|
if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
|
||||||
bool=true
|
bool=true
|
||||||
[[ "${list}" == "${whitelist}" && -z "${type}" ]] && type="--whitelist-only"
|
[[ "${list}" == "${whitelist}" && -z "${type}" ]] && type="--whitelist-only"
|
||||||
[[ "${list}" == "${blacklist}" && -z "${type}" ]] && type="--blacklist-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
|
# 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
|
grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
|
||||||
if [[ "${bool}" == true ]]; then
|
if [[ "${bool}" == true ]]; then
|
||||||
# Remove it from the other one
|
# Remove it from the other one
|
||||||
echo -e " ${INFO} Removing $1 from $listname..."
|
echo -e " ${INFO} Removing $1 from ${listname}..."
|
||||||
# /I flag: search case-insensitive
|
# /I flag: search case-insensitive
|
||||||
sed -i "/${domain}/Id" "${list}"
|
sed -i "/${domain}/Id" "${list}"
|
||||||
reload=true
|
reload=true
|
||||||
else
|
else
|
||||||
if [[ "${verbose}" == true ]]; then
|
if [[ "${verbose}" == true ]]; then
|
||||||
echo -e " ${INFO} ${1} does not exist in ${listname}, no need to remove!"
|
echo -e " ${INFO} ${1} does not exist in ${listname}, no need to remove!"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
elif [[ "${list}" == "${regexlist}" ]]; then
|
||||||
|
[[ -z "${type}" ]] && type="--wildcard-only"
|
||||||
|
domain="${1}"
|
||||||
|
|
||||||
|
[[ "${wildcard}" == true ]] && domain="(^|\\.)${domain//\./\\.}$"
|
||||||
|
|
||||||
|
bool=true
|
||||||
|
# Is it in the list?
|
||||||
|
grep -Fx "${domain}" "${regexlist}" > /dev/null 2>&1 || bool=false
|
||||||
|
if [[ "${bool}" == true ]]; then
|
||||||
|
# Remove it from the other one
|
||||||
|
echo -e " ${INFO} Removing $domain from regex list..."
|
||||||
|
local lineNumber
|
||||||
|
lineNumber=$(grep -Fnx "$domain" "${list}" | cut -f1 -d:)
|
||||||
|
sed -i "${lineNumber}d" "${list}"
|
||||||
|
reload=true
|
||||||
|
else
|
||||||
|
if [[ "${verbose}" == true ]]; then
|
||||||
|
echo -e " ${INFO} ${domain} does not exist in regex list, no need to remove!"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
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
|
# Update Gravity
|
||||||
Reload() {
|
Reload() {
|
||||||
echo ""
|
echo ""
|
||||||
pihole -g --skip-download "${type:-}"
|
pihole -g --skip-download "${type:-}"
|
||||||
}
|
}
|
||||||
|
|
||||||
Displaylist() {
|
Displaylist() {
|
||||||
if [[ -f ${listMain} ]]; then
|
if [[ -f ${listMain} ]]; then
|
||||||
if [[ "${listMain}" == "${whitelist}" ]]; then
|
if [[ "${listMain}" == "${whitelist}" ]]; then
|
||||||
string="gravity resistant domains"
|
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 || [ -n "${RD}" ]; do
|
||||||
|
echo " ${count}: ${RD}"
|
||||||
|
count=$((count+1))
|
||||||
|
done < "${listMain}"
|
||||||
else
|
else
|
||||||
string="domains caught in the sinkhole"
|
echo -e " ${COL_LIGHT_RED}${listMain} does not exist!${COL_NC}"
|
||||||
fi
|
fi
|
||||||
verbose=false
|
exit 0;
|
||||||
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() {
|
NukeList() {
|
||||||
if [[ -f "${listMain}" ]]; then
|
if [[ -f "${listMain}" ]]; then
|
||||||
# Back up original list
|
# Back up original list
|
||||||
cp "${listMain}" "${listMain}.bck~"
|
cp "${listMain}" "${listMain}.bck~"
|
||||||
# Empty out file
|
# Empty out file
|
||||||
echo "" > "${listMain}"
|
echo "" > "${listMain}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
for var in "$@"; do
|
for var in "$@"; do
|
||||||
case "${var}" in
|
case "${var}" in
|
||||||
"-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";;
|
"-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";;
|
||||||
"-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";;
|
"-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";;
|
||||||
"-wild" | "wildcard" ) listMain="${wildcardlist}";;
|
"--wild" | "wildcard" ) listMain="${regexlist}"; wildcard=true;;
|
||||||
"-nr"| "--noreload" ) reload=false;;
|
"--regex" | "regex" ) listMain="${regexlist}";;
|
||||||
"-d" | "--delmode" ) addmode=false;;
|
"-nr"| "--noreload" ) reload=false;;
|
||||||
"-q" | "--quiet" ) verbose=false;;
|
"-d" | "--delmode" ) addmode=false;;
|
||||||
"-h" | "--help" ) helpFunc;;
|
"-q" | "--quiet" ) verbose=false;;
|
||||||
"-l" | "--list" ) Displaylist;;
|
"-h" | "--help" ) helpFunc;;
|
||||||
"--nuke" ) NukeList;;
|
"-l" | "--list" ) Displaylist;;
|
||||||
* ) HandleOther "${var}";;
|
"--nuke" ) NukeList;;
|
||||||
esac
|
* ) HandleOther "${var}";;
|
||||||
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
shift
|
shift
|
||||||
|
|
||||||
if [[ $# = 0 ]]; then
|
if [[ $# = 0 ]]; then
|
||||||
helpFunc
|
helpFunc
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PoplistFile
|
PoplistFile
|
||||||
|
|
||||||
if [[ "${reload}" != false ]]; then
|
if [[ "${reload}" != false ]]; then
|
||||||
# Ensure that "restart" is used for Wildcard updates
|
# Ensure that "restart" is used for Wildcard updates
|
||||||
Reload "${reload}"
|
Reload "${reload}"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -17,346 +17,179 @@ source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||||
# piholeGitURL set in basic-install.sh
|
# piholeGitURL set in basic-install.sh
|
||||||
# is_repo() sourced from basic-install.sh
|
# is_repo() sourced from basic-install.sh
|
||||||
# setupVars set in basic-install.sh
|
# setupVars set in basic-install.sh
|
||||||
|
# check_download_exists sourced from basic-install.sh
|
||||||
|
# fully_fetch_repo sourced from basic-install.sh
|
||||||
|
# get_available_branches sourced from basic-install.sh
|
||||||
|
# fetch_checkout_pull_branch sourced from basic-install.sh
|
||||||
|
# checkout_pull_branch sourced from basic-install.sh
|
||||||
|
|
||||||
source "${setupVars}"
|
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() {
|
warning1() {
|
||||||
echo " Please note that changing branches severely alters your Pi-hole subsystems"
|
echo " Please note that changing branches severely alters your Pi-hole subsystems"
|
||||||
echo " Features that work on the master branch, may not on a development branch"
|
echo " Features that work on the master branch, may not on a development branch"
|
||||||
echo -e " ${COL_LIGHT_RED}This feature is NOT supported unless a Pi-hole developer explicitly asks!${COL_NC}"
|
echo -e " ${COL_LIGHT_RED}This feature is NOT supported unless a Pi-hole developer explicitly asks!${COL_NC}"
|
||||||
read -r -p " Have you read and understood this? [y/N] " response
|
read -r -p " Have you read and understood this? [y/N] " response
|
||||||
case "${response}" in
|
case "${response}" in
|
||||||
[yY][eE][sS]|[yY])
|
[yY][eE][sS]|[yY])
|
||||||
echo ""
|
echo ""
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo -e "\\n ${INFO} Branch change has been cancelled"
|
echo -e "\\n ${INFO} Branch change has been cancelled"
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
checkout() {
|
checkout() {
|
||||||
local corebranches
|
local corebranches
|
||||||
local webbranches
|
local webbranches
|
||||||
|
|
||||||
# Avoid globbing
|
# Avoid globbing
|
||||||
set -f
|
set -f
|
||||||
|
|
||||||
# This is unlikely
|
# This is unlikely
|
||||||
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||||
echo -e " ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!
|
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}"
|
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
|
||||||
exit 1;
|
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
|
||||||
fi
|
if [[ "${INSTALL_WEB_INTERFACE}" == "true" ]]; then
|
||||||
|
if ! is_repo "${webInterfaceDir}" ; then
|
||||||
if [[ -z "${1}" ]]; then
|
echo -e " ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!"
|
||||||
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}
|
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
|
||||||
Try 'pihole checkout --help' for more information."
|
exit 1;
|
||||||
exit 1
|
fi
|
||||||
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}"
|
|
||||||
echo "development" > /etc/pihole/ftlbranch
|
|
||||||
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}"
|
|
||||||
echo "master" > /etc/pihole/ftlbranch
|
|
||||||
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
|
fi
|
||||||
|
|
||||||
echo ""
|
if [[ -z "${1}" ]]; then
|
||||||
# Have the user choose the branch they want
|
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}"
|
||||||
if ! (for e in "${corebranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
|
echo -e " Try 'pihole checkout --help' for more information."
|
||||||
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"
|
|
||||||
echo "${2}" > /etc/pihole/ftlbranch
|
|
||||||
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
if ! warning1 ; then
|
||||||
echo -e " ${INFO} Requested option \"${1}\" is not available"
|
exit 1
|
||||||
exit 1
|
fi
|
||||||
fi
|
|
||||||
|
if [[ "${1}" == "dev" ]] ; then
|
||||||
# Force updating everything
|
# Shortcut to check out development branches
|
||||||
if [[ ( ! "${1}" == "web" && ! "${1}" == "ftl" ) && "${update}" == "true" ]]; then
|
echo -e " ${INFO} Shortcut \"dev\" detected - checking out development / devel branches..."
|
||||||
echo -e " ${INFO} Running installer to upgrade your installation"
|
echo ""
|
||||||
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
|
echo -e " ${INFO} Pi-hole Core"
|
||||||
exit 0
|
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core developement branch"; exit 1; }
|
||||||
else
|
if [[ "${INSTALL_WEB_INTERFACE}" == "true" ]]; then
|
||||||
echo -e " ${COL_LIGHT_RED} Error: Unable to complete update, please contact support${COL_NC}"
|
echo ""
|
||||||
exit 1
|
echo -e " ${INFO} Web interface"
|
||||||
|
fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; }
|
||||||
|
fi
|
||||||
|
#echo -e " ${TICK} Pi-hole Core"
|
||||||
|
|
||||||
|
get_binary_name
|
||||||
|
local path
|
||||||
|
path="development/${binary}"
|
||||||
|
echo "development" > /etc/pihole/ftlbranch
|
||||||
|
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_INTERFACE} == "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}"
|
||||||
|
echo "master" > /etc/pihole/ftlbranch
|
||||||
|
elif [[ "${1}" == "core" ]] ; then
|
||||||
|
str="Fetching branches from ${piholeGitUrl}"
|
||||||
|
echo -ne " ${INFO} $str"
|
||||||
|
if ! fully_fetch_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||||
|
echo -e "${OVER} ${CROSS} $str"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}"))
|
||||||
|
|
||||||
|
if [[ "${corebranches[*]}" == *"master"* ]]; then
|
||||||
|
echo -e "${OVER} ${TICK} $str"
|
||||||
|
echo -e "${INFO} ${#corebranches[@]} branches available for Pi-hole Core"
|
||||||
|
else
|
||||||
|
# Print STDERR output from get_available_branches
|
||||||
|
echo -e "${OVER} ${CROSS} $str\\n\\n${corebranches[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
# Have the user choose the branch they want
|
||||||
|
if ! (for e in "${corebranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
|
||||||
|
echo -e " ${INFO} Requested branch \"${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_INTERFACE}" == "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"
|
||||||
|
echo -e "${INFO} ${#webbranches[@]} branches available for Web Admin"
|
||||||
|
else
|
||||||
|
# Print STDERR output from get_available_branches
|
||||||
|
echo -e "${OVER} ${CROSS} $str\\n\\n${webbranches[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
# Have the user choose the branch they want
|
||||||
|
if ! (for e in "${webbranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
|
||||||
|
echo -e " ${INFO} Requested branch \"${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"
|
||||||
|
echo "${2}" > /etc/pihole/ftlbranch
|
||||||
|
FTLinstall "${binary}"
|
||||||
|
start_service pihole-FTL
|
||||||
|
enable_service pihole-FTL
|
||||||
|
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" ]]; 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
|
fi
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -16,48 +16,51 @@ source ${colfile}
|
||||||
# Constructed to return nothing when
|
# Constructed to return nothing when
|
||||||
# a) the setting is not present in the config file, or
|
# a) the setting is not present in the config file, or
|
||||||
# b) the setting is commented out (e.g. "#DBFILE=...")
|
# b) the setting is commented out (e.g. "#DBFILE=...")
|
||||||
DBFILE="$(sed -n -e 's/^\s^.DBFILE\s*=\s*//p' /etc/pihole/pihole-FTL.conf)"
|
FTLconf="/etc/pihole/pihole-FTL.conf"
|
||||||
|
if [ -e "$FTLconf" ]; then
|
||||||
|
DBFILE="$(sed -n -e 's/^\s*DBFILE\s*=\s*//p' ${FTLconf})"
|
||||||
|
fi
|
||||||
# Test for empty string. Use standard path in this case.
|
# Test for empty string. Use standard path in this case.
|
||||||
if [ -z "$DBFILE" ]; then
|
if [ -z "$DBFILE" ]; then
|
||||||
DBFILE="/etc/pihole/pihole-FTL.db"
|
DBFILE="/etc/pihole/pihole-FTL.db"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$@" != *"quiet"* ]]; then
|
if [[ "$@" != *"quiet"* ]]; then
|
||||||
echo -ne " ${INFO} Flushing /var/log/pihole.log ..."
|
echo -ne " ${INFO} Flushing /var/log/pihole.log ..."
|
||||||
fi
|
fi
|
||||||
if [[ "$@" == *"once"* ]]; then
|
if [[ "$@" == *"once"* ]]; then
|
||||||
# Nightly logrotation
|
# Nightly logrotation
|
||||||
if command -v /usr/sbin/logrotate >/dev/null; then
|
if command -v /usr/sbin/logrotate >/dev/null; then
|
||||||
# Logrotate once
|
# Logrotate once
|
||||||
/usr/sbin/logrotate --force /etc/pihole/logrotate
|
/usr/sbin/logrotate --force /etc/pihole/logrotate
|
||||||
else
|
else
|
||||||
# Copy pihole.log over to pihole.log.1
|
# Copy pihole.log over to pihole.log.1
|
||||||
# and empty out pihole.log
|
# and empty out pihole.log
|
||||||
# Note that moving the file is not an option, as
|
# Note that moving the file is not an option, as
|
||||||
# dnsmasq would happily continue writing into the
|
# dnsmasq would happily continue writing into the
|
||||||
# moved file (it will have the same file handler)
|
# moved file (it will have the same file handler)
|
||||||
cp /var/log/pihole.log /var/log/pihole.log.1
|
cp /var/log/pihole.log /var/log/pihole.log.1
|
||||||
echo " " > /var/log/pihole.log
|
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
|
else
|
||||||
# Delete most recent 24 hours from FTL's database, leave even older data intact (don't wipe out all history)
|
# Manual flushing
|
||||||
deleted=$(sqlite3 "${DBFILE}" "DELETE FROM queries WHERE timestamp >= strftime('%s','now')-86400; select changes() from queries limit 1")
|
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
|
||||||
|
# Delete most recent 24 hours from FTL's database, leave even older data intact (don't wipe out all history)
|
||||||
|
deleted=$(sqlite3 "${DBFILE}" "DELETE FROM queries WHERE timestamp >= strftime('%s','now')-86400; select changes() from queries limit 1")
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$@" != *"quiet"* ]]; then
|
if [[ "$@" != *"quiet"* ]]; then
|
||||||
echo -e "${OVER} ${TICK} Flushed /var/log/pihole.log"
|
echo -e "${OVER} ${TICK} Flushed /var/log/pihole.log"
|
||||||
echo -e " ${TICK} Deleted ${deleted} queries from database"
|
echo -e " ${TICK} Deleted ${deleted} queries from database"
|
||||||
fi
|
fi
|
||||||
|
|
239
advanced/Scripts/query.sh
Normal file
239
advanced/Scripts/query.sh
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
|
# (c) 2018 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
# Network-wide ad blocking via your own hardware.
|
||||||
|
#
|
||||||
|
# Query Domain Lists
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
# Globals
|
||||||
|
piholeDir="/etc/pihole"
|
||||||
|
adListsList="$piholeDir/adlists.list"
|
||||||
|
wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
|
||||||
|
options="$*"
|
||||||
|
adlist=""
|
||||||
|
all=""
|
||||||
|
exact=""
|
||||||
|
blockpage=""
|
||||||
|
matchType="match"
|
||||||
|
|
||||||
|
colfile="/opt/pihole/COL_TABLE"
|
||||||
|
source "${colfile}"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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 "$piholeDir" || exit 1
|
||||||
|
|
||||||
|
# Prevent grep -i matching slowly: http://bit.ly/2xFXtUX
|
||||||
|
export LC_CTYPE=C
|
||||||
|
|
||||||
|
# /dev/null forces filename to be printed when only one list has been generated
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
case "${type}" in
|
||||||
|
"exact" ) grep -i -E -l "(^|\\s)${domain}($|\\s|#)" ${lists} /dev/null 2>/dev/null;;
|
||||||
|
"wc" ) grep -i -o -m 1 "/${domain}/" ${lists} 2>/dev/null;;
|
||||||
|
* ) grep -i "${domain}" ${lists} /dev/null 2>/dev/null;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
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 "$adListsList" ]]; then
|
||||||
|
echo -e "${COL_LIGHT_RED}The file $adListsList 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 "$piholeDir" || exit 0; printf "%s\\n" -- *.domains | sort -V)")
|
||||||
|
|
||||||
|
# Query blocklists for occurences of domain
|
||||||
|
mapfile -t results <<< "$(scanList "${domainQuery}" "${lists[*]}" "${exact}")"
|
||||||
|
|
||||||
|
# Handle notices
|
||||||
|
if [[ -z "${wbMatch:-}" ]] && [[ -z "${wcMatch:-}" ]] && [[ -z "${results[*]}" ]]; then
|
||||||
|
echo -e " ${INFO} No ${exact/t/t }results found for ${COL_BOLD}${domainQuery}${COL_NC} within the block lists"
|
||||||
|
exit 0
|
||||||
|
elif [[ -z "${results[*]}" ]]; then
|
||||||
|
# Result found in WL/BL/Wildcards
|
||||||
|
exit 0
|
||||||
|
elif [[ -z "${all}" ]] && [[ "${#results[*]}" -ge 100 ]]; then
|
||||||
|
echo -e " ${INFO} Over 100 ${exact/t/t }results found for ${COL_BOLD}${domainQuery}${COL_NC}
|
||||||
|
This can be overridden using the -all option"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove unwanted content from non-exact $results
|
||||||
|
if [[ -z "${exact}" ]]; then
|
||||||
|
# Delete lines starting with #
|
||||||
|
# Remove comments after domain
|
||||||
|
# Remove hosts format IP address
|
||||||
|
mapfile -t results <<< "$(IFS=$'\n'; sed \
|
||||||
|
-e "/:#/d" \
|
||||||
|
-e "s/[ \\t]#.*//g" \
|
||||||
|
-e "s/:.*[ \\t]/:/g" \
|
||||||
|
<<< "${results[*]}")"
|
||||||
|
# Exit if result was in a comment
|
||||||
|
[[ -z "${results[*]}" ]] && exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get adlist file content as array
|
||||||
|
if [[ -n "${adlist}" ]] || [[ -n "${blockpage}" ]]; then
|
||||||
|
for adlistUrl in $(< "${adListsList}"); 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
|
|
@ -15,28 +15,28 @@
|
||||||
# Borrowed from adafruit-pitft-helper < borrowed from raspi-config
|
# Borrowed from adafruit-pitft-helper < borrowed from raspi-config
|
||||||
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L324-L334
|
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L324-L334
|
||||||
getInitSys() {
|
getInitSys() {
|
||||||
if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then
|
if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then
|
||||||
SYSTEMD=1
|
SYSTEMD=1
|
||||||
elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then
|
elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then
|
||||||
SYSTEMD=0
|
SYSTEMD=0
|
||||||
else
|
else
|
||||||
echo "Unrecognised init system"
|
echo "Unrecognised init system"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Borrowed from adafruit-pitft-helper:
|
# Borrowed from adafruit-pitft-helper:
|
||||||
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L274-L285
|
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L274-L285
|
||||||
autoLoginPiToConsole() {
|
autoLoginPiToConsole() {
|
||||||
if [ -e /etc/init.d/lightdm ]; then
|
if [ -e /etc/init.d/lightdm ]; then
|
||||||
if [ ${SYSTEMD} -eq 1 ]; then
|
if [ ${SYSTEMD} -eq 1 ]; then
|
||||||
systemctl set-default multi-user.target
|
systemctl set-default multi-user.target
|
||||||
ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
|
ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
|
||||||
else
|
else
|
||||||
update-rc.d lightdm disable 2
|
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/"
|
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
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
######### SCRIPT ###########
|
######### SCRIPT ###########
|
||||||
|
|
|
@ -19,6 +19,9 @@ readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
PH_TEST=true
|
PH_TEST=true
|
||||||
|
|
||||||
|
# when --check-only is passed to this script, it will not perform the actual update
|
||||||
|
CHECK_ONLY=false
|
||||||
|
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
|
@ -28,201 +31,161 @@ source "/opt/pihole/COL_TABLE"
|
||||||
# make_repo() sourced from basic-install.sh
|
# make_repo() sourced from basic-install.sh
|
||||||
# update_repo() source from basic-install.sh
|
# update_repo() source from basic-install.sh
|
||||||
# getGitFiles() sourced from basic-install.sh
|
# getGitFiles() sourced from basic-install.sh
|
||||||
|
# get_binary_name() sourced from basic-install.sh
|
||||||
|
# FTLcheckUpdate() sourced from basic-install.sh
|
||||||
|
|
||||||
GitCheckUpdateAvail() {
|
GitCheckUpdateAvail() {
|
||||||
local directory="${1}"
|
local directory
|
||||||
curdir=$PWD
|
directory="${1}"
|
||||||
cd "${directory}" || return
|
curdir=$PWD
|
||||||
|
cd "${directory}" || return
|
||||||
|
|
||||||
# Fetch latest changes in this repo
|
# Fetch latest changes in this repo
|
||||||
git fetch --quiet origin
|
git fetch --quiet origin
|
||||||
|
|
||||||
# @ alone is a shortcut for HEAD. Older versions of git
|
# @ alone is a shortcut for HEAD. Older versions of git
|
||||||
# need @{0}
|
# need @{0}
|
||||||
LOCAL="$(git rev-parse "@{0}")"
|
LOCAL="$(git rev-parse "@{0}")"
|
||||||
|
|
||||||
# The suffix @{upstream} to a branchname
|
# The suffix @{upstream} to a branchname
|
||||||
# (short form <branchname>@{u}) refers
|
# (short form <branchname>@{u}) refers
|
||||||
# to the branch that the branch specified
|
# to the branch that the branch specified
|
||||||
# by branchname is set to build on top of#
|
# by branchname is set to build on top of#
|
||||||
# (configured with branch.<name>.remote and
|
# (configured with branch.<name>.remote and
|
||||||
# branch.<name>.merge). A missing branchname
|
# branch.<name>.merge). A missing branchname
|
||||||
# defaults to the current one.
|
# defaults to the current one.
|
||||||
REMOTE="$(git rev-parse "@{upstream}")"
|
REMOTE="$(git rev-parse "@{upstream}")"
|
||||||
|
|
||||||
if [[ "${#LOCAL}" == 0 ]]; then
|
if [[ "${#LOCAL}" == 0 ]]; then
|
||||||
echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support
|
echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support"
|
||||||
Additional debugging output:${COL_NC}"
|
echo -e " Additional debugging output:${COL_NC}"
|
||||||
git status
|
git status
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
if [[ "${#REMOTE}" == 0 ]]; then
|
if [[ "${#REMOTE}" == 0 ]]; then
|
||||||
echo -e "\\n ${COL_LIGHT_RED}Error: Remote revision could not be obtained, please contact Pi-hole Support
|
echo -e "\\n ${COL_LIGHT_RED}Error: Remote revision could not be obtained, please contact Pi-hole Support"
|
||||||
Additional debugging output:${COL_NC}"
|
echo -e " Additional debugging output:${COL_NC}"
|
||||||
git status
|
git status
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Change back to original directory
|
# Change back to original directory
|
||||||
cd "${curdir}" || exit
|
cd "${curdir}" || exit
|
||||||
|
|
||||||
if [[ "${LOCAL}" != "${REMOTE}" ]]; then
|
if [[ "${LOCAL}" != "${REMOTE}" ]]; then
|
||||||
# Local branch is behind remote branch -> Update
|
# Local branch is behind remote branch -> Update
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
# Local branch is up-to-date or in a situation
|
# Local branch is up-to-date or in a situation
|
||||||
# where this updater cannot be used (like on a
|
# where this updater cannot be used (like on a
|
||||||
# branch that exists only locally)
|
# branch that exists only locally)
|
||||||
return 1
|
return 1
|
||||||
fi
|
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() {
|
main() {
|
||||||
local pihole_version_current
|
local basicError="\\n ${COL_LIGHT_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
|
||||||
local web_version_current
|
local core_update
|
||||||
local basicError="\\n ${COL_LIGHT_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
|
local web_update
|
||||||
|
local FTL_update
|
||||||
# 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
|
core_update=false
|
||||||
echo -e " ${INFO} Pi-hole Core:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
web_update=false
|
||||||
fi
|
|
||||||
|
|
||||||
if FTLcheckUpdate ; then
|
|
||||||
FTL_update=true
|
|
||||||
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
|
|
||||||
else
|
|
||||||
FTL_update=false
|
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
|
# shellcheck disable=1090,2154
|
||||||
# since the core update will run the installer which will itself
|
source "${setupVars}"
|
||||||
# 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
|
# This is unlikely
|
||||||
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
|
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||||
echo -e "\\n ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!
|
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}"
|
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if GitCheckUpdateAvail "${ADMIN_INTERFACE_DIR}" ; then
|
echo -e " ${INFO} Checking for updates..."
|
||||||
web_update=true
|
|
||||||
echo -e " ${INFO} Web Interface:\\t${COL_YELLOW}update available${COL_NC}"
|
if GitCheckUpdateAvail "${PI_HOLE_FILES_DIR}" ; then
|
||||||
|
core_update=true
|
||||||
|
echo -e " ${INFO} Pi-hole Core:\\t${COL_YELLOW}update available${COL_NC}"
|
||||||
else
|
else
|
||||||
web_update=false
|
core_update=false
|
||||||
echo -e " ${INFO} Web Interface:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
echo -e " ${INFO} Pi-hole Core:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Logic
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
# If Core up to date AND web up to date:
|
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
|
||||||
# Do nothing
|
echo -e "\\n ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!"
|
||||||
# If Core up to date AND web NOT up to date:
|
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
|
||||||
# Pull web repo
|
exit 1;
|
||||||
# If Core NOT up to date AND web up to date:
|
fi
|
||||||
# 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 GitCheckUpdateAvail "${ADMIN_INTERFACE_DIR}" ; then
|
||||||
if ! ${FTL_update} ; then
|
web_update=true
|
||||||
|
echo -e " ${INFO} Web Interface:\\t${COL_YELLOW}update available${COL_NC}"
|
||||||
|
else
|
||||||
|
web_update=false
|
||||||
|
echo -e " ${INFO} Web Interface:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if FTLcheckUpdate > /dev/null; then
|
||||||
|
FTL_update=true
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
|
||||||
|
else
|
||||||
|
case $? in
|
||||||
|
1)
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Branch is not available.${COL_NC}\\n\\t\\t\\tUse ${COL_LIGHT_GREEN}pihole checkout ftl [branchname]${COL_NC} to switch to a valid branch."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Something has gone wrong, contact support${COL_NC}"
|
||||||
|
esac
|
||||||
|
FTL_update=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${core_update}" == false && "${web_update}" == false && "${FTL_update}" == false ]]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${TICK} Everything is up to date!"
|
echo -e " ${TICK} Everything is up to date!"
|
||||||
exit 0
|
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
|
fi
|
||||||
else # Web Admin not installed, so only verify if core is up to date
|
|
||||||
if ! ${core_update}; then
|
if [[ "${CHECK_ONLY}" == true ]]; then
|
||||||
if ! ${FTL_update} ; then
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${INFO} Everything is up to date!"
|
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
echo ""
|
if [[ "${core_update}" == true ]]; then
|
||||||
echo -e " ${INFO} Pi-hole Core files out of date"
|
echo ""
|
||||||
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
|
echo -e " ${INFO} Pi-hole core files out of date, updating local repo."
|
||||||
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
|
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
|
||||||
|
echo -e " ${INFO} If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${web_update}" == true ]]; then
|
||||||
|
echo ""
|
||||||
|
echo -e " ${INFO} Pi-hole Web Admin files out of date, updating local repo."
|
||||||
|
getGitFiles "${ADMIN_INTERFACE_DIR}" "${ADMIN_INTERFACE_GIT_URL}"
|
||||||
|
echo -e " ${INFO} If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${FTL_update}" == true ]]; then
|
||||||
|
echo ""
|
||||||
|
echo -e " ${INFO} FTL out of date, it will be updated by the installer."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then
|
||||||
|
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
|
||||||
echo -e "${basicError}" && exit 1
|
echo -e "${basicError}" && exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${web_update}" == true ]]; then
|
|
||||||
web_version_current="$(/usr/local/bin/pihole version --admin --current)"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${INFO} Web Admin version is now at ${web_version_current/* v/v}
|
exit 0
|
||||||
${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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if [[ "$1" == "--check-only" ]]; then
|
||||||
|
CHECK_ONLY=true
|
||||||
|
fi
|
||||||
|
|
||||||
main
|
main
|
||||||
|
|
|
@ -10,57 +10,57 @@
|
||||||
|
|
||||||
# Credit: https://stackoverflow.com/a/46324904
|
# Credit: https://stackoverflow.com/a/46324904
|
||||||
function json_extract() {
|
function json_extract() {
|
||||||
local key=$1
|
local key=$1
|
||||||
local json=$2
|
local json=$2
|
||||||
|
|
||||||
local string_regex='"([^"\]|\\.)*"'
|
local string_regex='"([^"\]|\\.)*"'
|
||||||
local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
|
local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
|
||||||
local value_regex="${string_regex}|${number_regex}|true|false|null"
|
local value_regex="${string_regex}|${number_regex}|true|false|null"
|
||||||
local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"
|
local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"
|
||||||
|
|
||||||
if [[ ${json} =~ ${pair_regex} ]]; then
|
if [[ ${json} =~ ${pair_regex} ]]; then
|
||||||
echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
|
echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_local_branch() {
|
function get_local_branch() {
|
||||||
# Return active branch
|
# Return active branch
|
||||||
cd "${1}" 2> /dev/null || return 1
|
cd "${1}" 2> /dev/null || return 1
|
||||||
git rev-parse --abbrev-ref HEAD || return 1
|
git rev-parse --abbrev-ref HEAD || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_local_version() {
|
function get_local_version() {
|
||||||
# Return active branch
|
# Return active branch
|
||||||
cd "${1}" 2> /dev/null || return 1
|
cd "${1}" 2> /dev/null || return 1
|
||||||
git describe --long --dirty --tags || return 1
|
git describe --long --dirty --tags || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ "$2" == "remote" ]]; then
|
if [[ "$2" == "remote" ]]; then
|
||||||
|
|
||||||
if [[ "$3" == "reboot" ]]; then
|
if [[ "$3" == "reboot" ]]; then
|
||||||
sleep 30
|
sleep 30
|
||||||
fi
|
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_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_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)")"
|
GITHUB_FTL_VERSION="$(json_extract tag_name "$(curl -q 'https://api.github.com/repos/pi-hole/FTL/releases/latest' 2> /dev/null)")"
|
||||||
|
|
||||||
echo -n "${GITHUB_CORE_VERSION} ${GITHUB_WEB_VERSION} ${GITHUB_FTL_VERSION}" > "/etc/pihole/GitHubVersions"
|
echo -n "${GITHUB_CORE_VERSION} ${GITHUB_WEB_VERSION} ${GITHUB_FTL_VERSION}" > "/etc/pihole/GitHubVersions"
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
CORE_BRANCH="$(get_local_branch /etc/.pihole)"
|
CORE_BRANCH="$(get_local_branch /etc/.pihole)"
|
||||||
WEB_BRANCH="$(get_local_branch /var/www/html/admin)"
|
WEB_BRANCH="$(get_local_branch /var/www/html/admin)"
|
||||||
FTL_BRANCH="$(pihole-FTL branch)"
|
FTL_BRANCH="$(pihole-FTL branch)"
|
||||||
|
|
||||||
echo -n "${CORE_BRANCH} ${WEB_BRANCH} ${FTL_BRANCH}" > "/etc/pihole/localbranches"
|
echo -n "${CORE_BRANCH} ${WEB_BRANCH} ${FTL_BRANCH}" > "/etc/pihole/localbranches"
|
||||||
|
|
||||||
CORE_VERSION="$(get_local_version /etc/.pihole)"
|
CORE_VERSION="$(get_local_version /etc/.pihole)"
|
||||||
WEB_VERSION="$(get_local_version /var/www/html/admin)"
|
WEB_VERSION="$(get_local_version /var/www/html/admin)"
|
||||||
FTL_VERSION="$(pihole-FTL version)"
|
FTL_VERSION="$(pihole-FTL version)"
|
||||||
|
|
||||||
echo -n "${CORE_VERSION} ${WEB_VERSION} ${FTL_VERSION}" > "/etc/pihole/localversions"
|
echo -n "${CORE_VERSION} ${WEB_VERSION} ${FTL_VERSION}" > "/etc/pihole/localversions"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -14,135 +14,135 @@ COREGITDIR="/etc/.pihole/"
|
||||||
WEBGITDIR="/var/www/html/admin/"
|
WEBGITDIR="/var/www/html/admin/"
|
||||||
|
|
||||||
getLocalVersion() {
|
getLocalVersion() {
|
||||||
# FTL requires a different method
|
# FTL requires a different method
|
||||||
if [[ "$1" == "FTL" ]]; then
|
if [[ "$1" == "FTL" ]]; then
|
||||||
pihole-FTL version
|
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
|
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() {
|
getLocalHash() {
|
||||||
# Local FTL hash does not exist on filesystem
|
# Local FTL hash does not exist on filesystem
|
||||||
if [[ "$1" == "FTL" ]]; then
|
if [[ "$1" == "FTL" ]]; then
|
||||||
echo "N/A"
|
echo "N/A"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get the short hash of the local repository
|
|
||||||
local directory="${1}"
|
|
||||||
local hash
|
|
||||||
|
|
||||||
cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
|
# Get the short hash of the local repository
|
||||||
hash=$(git rev-parse --short HEAD || echo "$DEFAULT")
|
local directory="${1}"
|
||||||
if [[ "${hash}" == "${DEFAULT}" ]]; then
|
local hash
|
||||||
echo "ERROR"
|
|
||||||
return 1
|
cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
|
||||||
else
|
hash=$(git rev-parse --short HEAD || echo "$DEFAULT")
|
||||||
echo "${hash}"
|
if [[ "${hash}" == "${DEFAULT}" ]]; then
|
||||||
fi
|
echo "ERROR"
|
||||||
return 0
|
return 1
|
||||||
|
else
|
||||||
|
echo "${hash}"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
getRemoteHash(){
|
getRemoteHash(){
|
||||||
# Remote FTL hash is not applicable
|
# Remote FTL hash is not applicable
|
||||||
if [[ "$1" == "FTL" ]]; then
|
if [[ "$1" == "FTL" ]]; then
|
||||||
echo "N/A"
|
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
|
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(){
|
getRemoteVersion(){
|
||||||
# Get the version from the remote origin
|
# Get the version from the remote origin
|
||||||
local daemon="${1}"
|
local daemon="${1}"
|
||||||
local version
|
local version
|
||||||
|
|
||||||
version=$(curl --silent --fail "https://api.github.com/repos/pi-hole/${daemon}/releases/latest" | \
|
version=$(curl --silent --fail "https://api.github.com/repos/pi-hole/${daemon}/releases/latest" | \
|
||||||
awk -F: '$1 ~/tag_name/ { print $2 }' | \
|
awk -F: '$1 ~/tag_name/ { print $2 }' | \
|
||||||
tr -cd '[[:alnum:]]._-')
|
tr -cd '[[:alnum:]]._-')
|
||||||
if [[ "${version}" =~ ^v ]]; then
|
if [[ "${version}" =~ ^v ]]; then
|
||||||
echo "${version}"
|
echo "${version}"
|
||||||
else
|
else
|
||||||
echo "ERROR"
|
echo "ERROR"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
versionOutput() {
|
versionOutput() {
|
||||||
[[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
|
[[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
|
||||||
[[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
|
[[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
|
||||||
[[ "$1" == "FTL" ]] && GITDIR="FTL"
|
[[ "$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
|
[[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $GITDIR)
|
||||||
output="${1^} version is $current (Latest: $latest)"
|
[[ "$2" == "-l" ]] || [[ "$2" == "--latest" ]] || [[ -z "$2" ]] && latest=$(getRemoteVersion "$1")
|
||||||
elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then
|
if [[ "$2" == "-h" ]] || [[ "$2" == "--hash" ]]; then
|
||||||
output="Current ${1^} version is $current"
|
[[ "$3" == "-c" ]] || [[ "$3" == "--current" ]] || [[ -z "$3" ]] && curHash=$(getLocalHash "$GITDIR")
|
||||||
elif [[ -z "$current" ]] && [[ -n "$latest" ]]; then
|
[[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)")
|
||||||
output="Latest ${1^} version is $latest"
|
fi
|
||||||
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"
|
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() {
|
errorOutput() {
|
||||||
echo " Invalid Option! Try 'pihole -v --help' for more information."
|
echo " Invalid Option! Try 'pihole -v --help' for more information."
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultOutput() {
|
defaultOutput() {
|
||||||
versionOutput "pi-hole" "$@"
|
versionOutput "pi-hole" "$@"
|
||||||
versionOutput "AdminLTE" "$@"
|
versionOutput "AdminLTE" "$@"
|
||||||
versionOutput "FTL" "$@"
|
versionOutput "FTL" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
helpFunc() {
|
helpFunc() {
|
||||||
echo "Usage: pihole -v [repo | option] [option]
|
echo "Usage: pihole -v [repo | option] [option]
|
||||||
Example: 'pihole -v -p -l'
|
Example: 'pihole -v -p -l'
|
||||||
Show Pi-hole, Admin Console & FTL versions
|
Show Pi-hole, Admin Console & FTL versions
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ Repositories:
|
||||||
-p, --pihole Only retrieve info regarding Pi-hole repository
|
-p, --pihole Only retrieve info regarding Pi-hole repository
|
||||||
-a, --admin Only retrieve info regarding AdminLTE repository
|
-a, --admin Only retrieve info regarding AdminLTE repository
|
||||||
-f, --ftl Only retrieve info regarding FTL repository
|
-f, --ftl Only retrieve info regarding FTL repository
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-c, --current Return the current version
|
-c, --current Return the current version
|
||||||
-l, --latest Return the latest version
|
-l, --latest Return the latest version
|
||||||
|
@ -160,9 +160,9 @@ Options:
|
||||||
}
|
}
|
||||||
|
|
||||||
case "${1}" in
|
case "${1}" in
|
||||||
"-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";;
|
"-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";;
|
||||||
"-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";;
|
"-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";;
|
||||||
"-f" | "--ftl" ) shift; versionOutput "FTL" "$@";;
|
"-f" | "--ftl" ) shift; versionOutput "FTL" "$@";;
|
||||||
"-h" | "--help" ) helpFunc;;
|
"-h" | "--help" ) helpFunc;;
|
||||||
* ) defaultOutput "$@";;
|
* ) defaultOutput "$@";;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -13,16 +13,17 @@
|
||||||
readonly setupVars="/etc/pihole/setupVars.conf"
|
readonly setupVars="/etc/pihole/setupVars.conf"
|
||||||
readonly dnsmasqconfig="/etc/dnsmasq.d/01-pihole.conf"
|
readonly dnsmasqconfig="/etc/dnsmasq.d/01-pihole.conf"
|
||||||
readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf"
|
readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf"
|
||||||
|
readonly FTLconf="/etc/pihole/pihole-FTL.conf"
|
||||||
# 03 -> wildcards
|
# 03 -> wildcards
|
||||||
readonly dhcpstaticconfig="/etc/dnsmasq.d/04-pihole-static-dhcp.conf"
|
readonly dhcpstaticconfig="/etc/dnsmasq.d/04-pihole-static-dhcp.conf"
|
||||||
|
|
||||||
coltable="/opt/pihole/COL_TABLE"
|
coltable="/opt/pihole/COL_TABLE"
|
||||||
if [[ -f ${coltable} ]]; then
|
if [[ -f ${coltable} ]]; then
|
||||||
source ${coltable}
|
source ${coltable}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
helpFunc() {
|
helpFunc() {
|
||||||
echo "Usage: pihole -a [options]
|
echo "Usage: pihole -a [options]
|
||||||
Example: pihole -a -p password
|
Example: pihole -a -p password
|
||||||
Set options for the Admin Console
|
Set options for the Admin Console
|
||||||
|
|
||||||
|
@ -35,256 +36,278 @@ Options:
|
||||||
-e, email Set an administrative contact address for the Block Page
|
-e, email Set an administrative contact address for the Block Page
|
||||||
-h, --help Show this help dialog
|
-h, --help Show this help dialog
|
||||||
-i, interface Specify dnsmasq's interface listening behavior
|
-i, interface Specify dnsmasq's interface listening behavior
|
||||||
Add '-h' for more info on interface usage"
|
-l, privacylevel Set privacy level (0 = lowest, 3 = highest)"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
add_setting() {
|
add_setting() {
|
||||||
echo "${1}=${2}" >> "${setupVars}"
|
echo "${1}=${2}" >> "${setupVars}"
|
||||||
}
|
}
|
||||||
|
|
||||||
delete_setting() {
|
delete_setting() {
|
||||||
sed -i "/${1}/d" "${setupVars}"
|
sed -i "/${1}/d" "${setupVars}"
|
||||||
}
|
}
|
||||||
|
|
||||||
change_setting() {
|
change_setting() {
|
||||||
delete_setting "${1}"
|
delete_setting "${1}"
|
||||||
add_setting "${1}" "${2}"
|
add_setting "${1}" "${2}"
|
||||||
|
}
|
||||||
|
|
||||||
|
addFTLsetting() {
|
||||||
|
echo "${1}=${2}" >> "${FTLconf}"
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteFTLsetting() {
|
||||||
|
sed -i "/${1}/d" "${FTLconf}"
|
||||||
|
}
|
||||||
|
|
||||||
|
changeFTLsetting() {
|
||||||
|
deleteFTLsetting "${1}"
|
||||||
|
addFTLsetting "${1}" "${2}"
|
||||||
}
|
}
|
||||||
|
|
||||||
add_dnsmasq_setting() {
|
add_dnsmasq_setting() {
|
||||||
if [[ "${2}" != "" ]]; then
|
if [[ "${2}" != "" ]]; then
|
||||||
echo "${1}=${2}" >> "${dnsmasqconfig}"
|
echo "${1}=${2}" >> "${dnsmasqconfig}"
|
||||||
else
|
else
|
||||||
echo "${1}" >> "${dnsmasqconfig}"
|
echo "${1}" >> "${dnsmasqconfig}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
delete_dnsmasq_setting() {
|
delete_dnsmasq_setting() {
|
||||||
sed -i "/${1}/d" "${dnsmasqconfig}"
|
sed -i "/${1}/d" "${dnsmasqconfig}"
|
||||||
}
|
}
|
||||||
|
|
||||||
SetTemperatureUnit() {
|
SetTemperatureUnit() {
|
||||||
change_setting "TEMPERATUREUNIT" "${unit}"
|
change_setting "TEMPERATUREUNIT" "${unit}"
|
||||||
echo -e " ${TICK} Set temperature unit to ${unit}"
|
echo -e " ${TICK} Set temperature unit to ${unit}"
|
||||||
}
|
}
|
||||||
|
|
||||||
HashPassword() {
|
HashPassword() {
|
||||||
# Compute password hash twice to avoid rainbow table vulnerability
|
# Compute password hash twice to avoid rainbow table vulnerability
|
||||||
return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//')
|
return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//')
|
||||||
return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//')
|
return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//')
|
||||||
echo ${return}
|
echo ${return}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetWebPassword() {
|
SetWebPassword() {
|
||||||
if [ "${SUDO_USER}" == "www-data" ]; then
|
if [ "${SUDO_USER}" == "www-data" ]; then
|
||||||
echo "Security measure: user www-data is not allowed to change webUI password!"
|
echo "Security measure: user www-data is not allowed to change webUI password!"
|
||||||
echo "Exiting"
|
echo "Exiting"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${SUDO_USER}" == "lighttpd" ]; then
|
if [ "${SUDO_USER}" == "lighttpd" ]; then
|
||||||
echo "Security measure: user lighttpd is not allowed to change webUI password!"
|
echo "Security measure: user lighttpd is not allowed to change webUI password!"
|
||||||
echo "Exiting"
|
echo "Exiting"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if (( ${#args[2]} > 0 )) ; then
|
if (( ${#args[2]} > 0 )) ; then
|
||||||
readonly PASSWORD="${args[2]}"
|
readonly PASSWORD="${args[2]}"
|
||||||
readonly CONFIRM="${PASSWORD}"
|
readonly CONFIRM="${PASSWORD}"
|
||||||
else
|
else
|
||||||
# Prevents a bug if the user presses Ctrl+C and it continues to hide the text typed.
|
# 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
|
# 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
|
trap '{ echo -e "\nNo password will be set" ; stty sane ; exit 1; }' INT
|
||||||
read -s -p "Enter New Password (Blank for no password): " PASSWORD
|
read -s -p "Enter New Password (Blank for no password): " PASSWORD
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
if [ "${PASSWORD}" == "" ]; then
|
if [ "${PASSWORD}" == "" ]; then
|
||||||
change_setting "WEBPASSWORD" ""
|
change_setting "WEBPASSWORD" ""
|
||||||
echo -e " ${TICK} Password Removed"
|
echo -e " ${TICK} Password Removed"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
read -s -p "Confirm Password: " CONFIRM
|
read -s -p "Confirm Password: " CONFIRM
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
|
if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
|
||||||
hash=$(HashPassword "${PASSWORD}")
|
hash=$(HashPassword "${PASSWORD}")
|
||||||
# Save hash to file
|
# Save hash to file
|
||||||
change_setting "WEBPASSWORD" "${hash}"
|
change_setting "WEBPASSWORD" "${hash}"
|
||||||
echo -e " ${TICK} New password set"
|
echo -e " ${TICK} New password set"
|
||||||
else
|
else
|
||||||
echo -e " ${CROSS} Passwords don't match. Your password has not been changed"
|
echo -e " ${CROSS} Passwords don't match. Your password has not been changed"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessDNSSettings() {
|
ProcessDNSSettings() {
|
||||||
source "${setupVars}"
|
source "${setupVars}"
|
||||||
|
|
||||||
delete_dnsmasq_setting "server"
|
delete_dnsmasq_setting "server"
|
||||||
|
|
||||||
COUNTER=1
|
COUNTER=1
|
||||||
while [[ 1 ]]; do
|
while [[ 1 ]]; do
|
||||||
var=PIHOLE_DNS_${COUNTER}
|
var=PIHOLE_DNS_${COUNTER}
|
||||||
if [ -z "${!var}" ]; then
|
if [ -z "${!var}" ]; then
|
||||||
break;
|
break;
|
||||||
fi
|
fi
|
||||||
add_dnsmasq_setting "server" "${!var}"
|
add_dnsmasq_setting "server" "${!var}"
|
||||||
let COUNTER=COUNTER+1
|
let COUNTER=COUNTER+1
|
||||||
done
|
done
|
||||||
|
|
||||||
delete_dnsmasq_setting "domain-needed"
|
# The option LOCAL_DNS_PORT is deprecated
|
||||||
|
# We apply it once more, and then convert it into the current format
|
||||||
|
if [ ! -z "${LOCAL_DNS_PORT}" ]; then
|
||||||
|
add_dnsmasq_setting "server" "127.0.0.1#${LOCAL_DNS_PORT}"
|
||||||
|
add_setting "PIHOLE_DNS_${COUNTER}" "127.0.0.1#${LOCAL_DNS_PORT}"
|
||||||
|
delete_setting "LOCAL_DNS_PORT"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
|
delete_dnsmasq_setting "domain-needed"
|
||||||
add_dnsmasq_setting "domain-needed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
delete_dnsmasq_setting "bogus-priv"
|
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
|
||||||
|
add_dnsmasq_setting "domain-needed"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "${DNS_BOGUS_PRIV}" == true ]]; then
|
delete_dnsmasq_setting "bogus-priv"
|
||||||
add_dnsmasq_setting "bogus-priv"
|
|
||||||
fi
|
|
||||||
|
|
||||||
delete_dnsmasq_setting "dnssec"
|
if [[ "${DNS_BOGUS_PRIV}" == true ]]; then
|
||||||
delete_dnsmasq_setting "trust-anchor="
|
add_dnsmasq_setting "bogus-priv"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "${DNSSEC}" == true ]]; then
|
delete_dnsmasq_setting "dnssec"
|
||||||
echo "dnssec
|
delete_dnsmasq_setting "trust-anchor="
|
||||||
|
|
||||||
|
if [[ "${DNSSEC}" == true ]]; then
|
||||||
|
echo "dnssec
|
||||||
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
|
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
|
||||||
trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D
|
trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D
|
||||||
" >> "${dnsmasqconfig}"
|
" >> "${dnsmasqconfig}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
delete_dnsmasq_setting "host-record"
|
delete_dnsmasq_setting "host-record"
|
||||||
|
|
||||||
if [ ! -z "${HOSTRECORD}" ]; then
|
if [ ! -z "${HOSTRECORD}" ]; then
|
||||||
add_dnsmasq_setting "host-record" "${HOSTRECORD}"
|
add_dnsmasq_setting "host-record" "${HOSTRECORD}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Setup interface listening behavior of dnsmasq
|
# Setup interface listening behavior of dnsmasq
|
||||||
delete_dnsmasq_setting "interface"
|
delete_dnsmasq_setting "interface"
|
||||||
delete_dnsmasq_setting "local-service"
|
delete_dnsmasq_setting "local-service"
|
||||||
|
|
||||||
if [[ "${DNSMASQ_LISTENING}" == "all" ]]; then
|
if [[ "${DNSMASQ_LISTENING}" == "all" ]]; then
|
||||||
# Listen on all interfaces, permit all origins
|
# Listen on all interfaces, permit all origins
|
||||||
add_dnsmasq_setting "except-interface" "nonexisting"
|
add_dnsmasq_setting "except-interface" "nonexisting"
|
||||||
elif [[ "${DNSMASQ_LISTENING}" == "local" ]]; then
|
elif [[ "${DNSMASQ_LISTENING}" == "local" ]]; then
|
||||||
# Listen only on all interfaces, but only local subnets
|
# Listen only on all interfaces, but only local subnets
|
||||||
add_dnsmasq_setting "local-service"
|
add_dnsmasq_setting "local-service"
|
||||||
else
|
else
|
||||||
# Listen only on one interface
|
# Listen only on one interface
|
||||||
# Use eth0 as fallback interface if interface is missing in setupVars.conf
|
# Use eth0 as fallback interface if interface is missing in setupVars.conf
|
||||||
if [ -z "${PIHOLE_INTERFACE}" ]; then
|
if [ -z "${PIHOLE_INTERFACE}" ]; then
|
||||||
PIHOLE_INTERFACE="eth0"
|
PIHOLE_INTERFACE="eth0"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
|
add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
|
||||||
fi
|
fi
|
||||||
if [[ "${CONDITIONAL_FORWARDING}" == true ]]; then
|
|
||||||
add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_DOMAIN}/${CONDITIONAL_FORWARDING_IP}"
|
|
||||||
add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_REVERSE}/${CONDITIONAL_FORWARDING_IP}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
if [[ "${CONDITIONAL_FORWARDING}" == true ]]; then
|
||||||
|
add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_DOMAIN}/${CONDITIONAL_FORWARDING_IP}"
|
||||||
|
add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_REVERSE}/${CONDITIONAL_FORWARDING_IP}"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
SetDNSServers() {
|
SetDNSServers() {
|
||||||
# Save setting to file
|
# Save setting to file
|
||||||
delete_setting "PIHOLE_DNS"
|
delete_setting "PIHOLE_DNS"
|
||||||
IFS=',' read -r -a array <<< "${args[2]}"
|
IFS=',' read -r -a array <<< "${args[2]}"
|
||||||
for index in "${!array[@]}"
|
for index in "${!array[@]}"
|
||||||
do
|
do
|
||||||
add_setting "PIHOLE_DNS_$((index+1))" "${array[index]}"
|
add_setting "PIHOLE_DNS_$((index+1))" "${array[index]}"
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ "${args[3]}" == "domain-needed" ]]; then
|
if [[ "${args[3]}" == "domain-needed" ]]; then
|
||||||
change_setting "DNS_FQDN_REQUIRED" "true"
|
change_setting "DNS_FQDN_REQUIRED" "true"
|
||||||
else
|
else
|
||||||
change_setting "DNS_FQDN_REQUIRED" "false"
|
change_setting "DNS_FQDN_REQUIRED" "false"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${args[4]}" == "bogus-priv" ]]; then
|
if [[ "${args[4]}" == "bogus-priv" ]]; then
|
||||||
change_setting "DNS_BOGUS_PRIV" "true"
|
change_setting "DNS_BOGUS_PRIV" "true"
|
||||||
else
|
else
|
||||||
change_setting "DNS_BOGUS_PRIV" "false"
|
change_setting "DNS_BOGUS_PRIV" "false"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${args[5]}" == "dnssec" ]]; then
|
if [[ "${args[5]}" == "dnssec" ]]; then
|
||||||
change_setting "DNSSEC" "true"
|
change_setting "DNSSEC" "true"
|
||||||
else
|
else
|
||||||
change_setting "DNSSEC" "false"
|
change_setting "DNSSEC" "false"
|
||||||
fi
|
fi
|
||||||
if [[ "${args[6]}" == "conditional_forwarding" ]]; then
|
|
||||||
change_setting "CONDITIONAL_FORWARDING" "true"
|
|
||||||
change_setting "CONDITIONAL_FORWARDING_IP" "${args[7]}"
|
|
||||||
change_setting "CONDITIONAL_FORWARDING_DOMAIN" "${args[8]}"
|
|
||||||
change_setting "CONDITIONAL_FORWARDING_REVERSE" "${args[9]}"
|
|
||||||
else
|
|
||||||
change_setting "CONDITIONAL_FORWARDING" "false"
|
|
||||||
delete_setting "CONDITIONAL_FORWARDING_IP"
|
|
||||||
delete_setting "CONDITIONAL_FORWARDING_DOMAIN"
|
|
||||||
delete_setting "CONDITIONAL_FORWARDING_REVERSE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ProcessDNSSettings
|
if [[ "${args[6]}" == "conditional_forwarding" ]]; then
|
||||||
|
change_setting "CONDITIONAL_FORWARDING" "true"
|
||||||
|
change_setting "CONDITIONAL_FORWARDING_IP" "${args[7]}"
|
||||||
|
change_setting "CONDITIONAL_FORWARDING_DOMAIN" "${args[8]}"
|
||||||
|
change_setting "CONDITIONAL_FORWARDING_REVERSE" "${args[9]}"
|
||||||
|
else
|
||||||
|
change_setting "CONDITIONAL_FORWARDING" "false"
|
||||||
|
delete_setting "CONDITIONAL_FORWARDING_IP"
|
||||||
|
delete_setting "CONDITIONAL_FORWARDING_DOMAIN"
|
||||||
|
delete_setting "CONDITIONAL_FORWARDING_REVERSE"
|
||||||
|
fi
|
||||||
|
|
||||||
# Restart dnsmasq to load new configuration
|
ProcessDNSSettings
|
||||||
RestartDNS
|
|
||||||
|
# Restart dnsmasq to load new configuration
|
||||||
|
RestartDNS
|
||||||
}
|
}
|
||||||
|
|
||||||
SetExcludeDomains() {
|
SetExcludeDomains() {
|
||||||
change_setting "API_EXCLUDE_DOMAINS" "${args[2]}"
|
change_setting "API_EXCLUDE_DOMAINS" "${args[2]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
SetExcludeClients() {
|
SetExcludeClients() {
|
||||||
change_setting "API_EXCLUDE_CLIENTS" "${args[2]}"
|
change_setting "API_EXCLUDE_CLIENTS" "${args[2]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
Poweroff(){
|
Poweroff(){
|
||||||
nohup bash -c "sleep 5; poweroff" &> /dev/null </dev/null &
|
nohup bash -c "sleep 5; poweroff" &> /dev/null </dev/null &
|
||||||
}
|
}
|
||||||
|
|
||||||
Reboot() {
|
Reboot() {
|
||||||
nohup bash -c "sleep 5; reboot" &> /dev/null </dev/null &
|
nohup bash -c "sleep 5; reboot" &> /dev/null </dev/null &
|
||||||
}
|
}
|
||||||
|
|
||||||
RestartDNS() {
|
RestartDNS() {
|
||||||
/usr/local/bin/pihole restartdns
|
/usr/local/bin/pihole restartdns
|
||||||
}
|
}
|
||||||
|
|
||||||
SetQueryLogOptions() {
|
SetQueryLogOptions() {
|
||||||
change_setting "API_QUERY_LOG_SHOW" "${args[2]}"
|
change_setting "API_QUERY_LOG_SHOW" "${args[2]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessDHCPSettings() {
|
ProcessDHCPSettings() {
|
||||||
source "${setupVars}"
|
source "${setupVars}"
|
||||||
|
|
||||||
if [[ "${DHCP_ACTIVE}" == "true" ]]; then
|
if [[ "${DHCP_ACTIVE}" == "true" ]]; then
|
||||||
interface="${PIHOLE_INTERFACE}"
|
interface="${PIHOLE_INTERFACE}"
|
||||||
|
|
||||||
# Use eth0 as fallback interface
|
# Use eth0 as fallback interface
|
||||||
if [ -z ${interface} ]; then
|
if [ -z ${interface} ]; then
|
||||||
interface="eth0"
|
interface="eth0"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${PIHOLE_DOMAIN}" == "" ]]; then
|
if [[ "${PIHOLE_DOMAIN}" == "" ]]; then
|
||||||
PIHOLE_DOMAIN="lan"
|
PIHOLE_DOMAIN="lan"
|
||||||
change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}"
|
change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${DHCP_LEASETIME}" == "0" ]]; then
|
if [[ "${DHCP_LEASETIME}" == "0" ]]; then
|
||||||
leasetime="infinite"
|
leasetime="infinite"
|
||||||
elif [[ "${DHCP_LEASETIME}" == "" ]]; then
|
elif [[ "${DHCP_LEASETIME}" == "" ]]; then
|
||||||
leasetime="24"
|
leasetime="24"
|
||||||
change_setting "DHCP_LEASETIME" "${leasetime}"
|
change_setting "DHCP_LEASETIME" "${leasetime}"
|
||||||
elif [[ "${DHCP_LEASETIME}" == "24h" ]]; then
|
elif [[ "${DHCP_LEASETIME}" == "24h" ]]; then
|
||||||
#Installation is affected by known bug, introduced in a previous version.
|
#Installation is affected by known bug, introduced in a previous version.
|
||||||
#This will automatically clean up setupVars.conf and remove the unnecessary "h"
|
#This will automatically clean up setupVars.conf and remove the unnecessary "h"
|
||||||
leasetime="24"
|
leasetime="24"
|
||||||
change_setting "DHCP_LEASETIME" "${leasetime}"
|
change_setting "DHCP_LEASETIME" "${leasetime}"
|
||||||
else
|
else
|
||||||
leasetime="${DHCP_LEASETIME}h"
|
leasetime="${DHCP_LEASETIME}h"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Write settings to file
|
# Write settings to file
|
||||||
|
@ -299,12 +322,12 @@ dhcp-leasefile=/etc/pihole/dhcp.leases
|
||||||
#quiet-dhcp
|
#quiet-dhcp
|
||||||
" > "${dhcpconfig}"
|
" > "${dhcpconfig}"
|
||||||
|
|
||||||
if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
|
if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
|
||||||
echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
|
echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${DHCP_IPv6}" == "true" ]]; then
|
if [[ "${DHCP_IPv6}" == "true" ]]; then
|
||||||
echo "#quiet-dhcp6
|
echo "#quiet-dhcp6
|
||||||
#enable-ra
|
#enable-ra
|
||||||
dhcp-option=option6:dns-server,[::]
|
dhcp-option=option6:dns-server,[::]
|
||||||
dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,${leasetime}
|
dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,${leasetime}
|
||||||
|
@ -312,158 +335,160 @@ ra-param=*,0,0
|
||||||
" >> "${dhcpconfig}"
|
" >> "${dhcpconfig}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
if [[ -f "${dhcpconfig}" ]]; then
|
if [[ -f "${dhcpconfig}" ]]; then
|
||||||
rm "${dhcpconfig}" &> /dev/null
|
rm "${dhcpconfig}" &> /dev/null
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
EnableDHCP() {
|
EnableDHCP() {
|
||||||
change_setting "DHCP_ACTIVE" "true"
|
change_setting "DHCP_ACTIVE" "true"
|
||||||
change_setting "DHCP_START" "${args[2]}"
|
change_setting "DHCP_START" "${args[2]}"
|
||||||
change_setting "DHCP_END" "${args[3]}"
|
change_setting "DHCP_END" "${args[3]}"
|
||||||
change_setting "DHCP_ROUTER" "${args[4]}"
|
change_setting "DHCP_ROUTER" "${args[4]}"
|
||||||
change_setting "DHCP_LEASETIME" "${args[5]}"
|
change_setting "DHCP_LEASETIME" "${args[5]}"
|
||||||
change_setting "PIHOLE_DOMAIN" "${args[6]}"
|
change_setting "PIHOLE_DOMAIN" "${args[6]}"
|
||||||
change_setting "DHCP_IPv6" "${args[7]}"
|
change_setting "DHCP_IPv6" "${args[7]}"
|
||||||
|
|
||||||
# Remove possible old setting from file
|
# Remove possible old setting from file
|
||||||
delete_dnsmasq_setting "dhcp-"
|
delete_dnsmasq_setting "dhcp-"
|
||||||
delete_dnsmasq_setting "quiet-dhcp"
|
delete_dnsmasq_setting "quiet-dhcp"
|
||||||
|
|
||||||
ProcessDHCPSettings
|
ProcessDHCPSettings
|
||||||
|
|
||||||
RestartDNS
|
RestartDNS
|
||||||
}
|
}
|
||||||
|
|
||||||
DisableDHCP() {
|
DisableDHCP() {
|
||||||
change_setting "DHCP_ACTIVE" "false"
|
change_setting "DHCP_ACTIVE" "false"
|
||||||
|
|
||||||
# Remove possible old setting from file
|
# Remove possible old setting from file
|
||||||
delete_dnsmasq_setting "dhcp-"
|
delete_dnsmasq_setting "dhcp-"
|
||||||
delete_dnsmasq_setting "quiet-dhcp"
|
delete_dnsmasq_setting "quiet-dhcp"
|
||||||
|
|
||||||
ProcessDHCPSettings
|
ProcessDHCPSettings
|
||||||
|
|
||||||
RestartDNS
|
RestartDNS
|
||||||
}
|
}
|
||||||
|
|
||||||
SetWebUILayout() {
|
SetWebUILayout() {
|
||||||
change_setting "WEBUIBOXEDLAYOUT" "${args[2]}"
|
change_setting "WEBUIBOXEDLAYOUT" "${args[2]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomizeAdLists() {
|
CustomizeAdLists() {
|
||||||
list="/etc/pihole/adlists.list"
|
list="/etc/pihole/adlists.list"
|
||||||
|
|
||||||
if [[ "${args[2]}" == "enable" ]]; then
|
if [[ "${args[2]}" == "enable" ]]; then
|
||||||
sed -i "\\@${args[3]}@s/^#http/http/g" "${list}"
|
sed -i "\\@${args[3]}@s/^#http/http/g" "${list}"
|
||||||
elif [[ "${args[2]}" == "disable" ]]; then
|
elif [[ "${args[2]}" == "disable" ]]; then
|
||||||
sed -i "\\@${args[3]}@s/^http/#http/g" "${list}"
|
sed -i "\\@${args[3]}@s/^http/#http/g" "${list}"
|
||||||
elif [[ "${args[2]}" == "add" ]]; then
|
elif [[ "${args[2]}" == "add" ]]; then
|
||||||
echo "${args[3]}" >> ${list}
|
if [[ $(grep -c "^${args[3]}$" "${list}") -eq 0 ]] ; then
|
||||||
elif [[ "${args[2]}" == "del" ]]; then
|
echo "${args[3]}" >> ${list}
|
||||||
var=$(echo "${args[3]}" | sed 's/\//\\\//g')
|
fi
|
||||||
sed -i "/${var}/Id" "${list}"
|
elif [[ "${args[2]}" == "del" ]]; then
|
||||||
else
|
var=$(echo "${args[3]}" | sed 's/\//\\\//g')
|
||||||
echo "Not permitted"
|
sed -i "/${var}/Id" "${list}"
|
||||||
return 1
|
else
|
||||||
fi
|
echo "Not permitted"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
SetPrivacyMode() {
|
SetPrivacyMode() {
|
||||||
if [[ "${args[2]}" == "true" ]]; then
|
if [[ "${args[2]}" == "true" ]]; then
|
||||||
change_setting "API_PRIVACY_MODE" "true"
|
change_setting "API_PRIVACY_MODE" "true"
|
||||||
else
|
else
|
||||||
change_setting "API_PRIVACY_MODE" "false"
|
change_setting "API_PRIVACY_MODE" "false"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolutionSettings() {
|
ResolutionSettings() {
|
||||||
typ="${args[2]}"
|
typ="${args[2]}"
|
||||||
state="${args[3]}"
|
state="${args[3]}"
|
||||||
|
|
||||||
if [[ "${typ}" == "forward" ]]; then
|
if [[ "${typ}" == "forward" ]]; then
|
||||||
change_setting "API_GET_UPSTREAM_DNS_HOSTNAME" "${state}"
|
change_setting "API_GET_UPSTREAM_DNS_HOSTNAME" "${state}"
|
||||||
elif [[ "${typ}" == "clients" ]]; then
|
elif [[ "${typ}" == "clients" ]]; then
|
||||||
change_setting "API_GET_CLIENT_HOSTNAME" "${state}"
|
change_setting "API_GET_CLIENT_HOSTNAME" "${state}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDHCPStaticAddress() {
|
AddDHCPStaticAddress() {
|
||||||
mac="${args[2]}"
|
mac="${args[2]}"
|
||||||
ip="${args[3]}"
|
ip="${args[3]}"
|
||||||
host="${args[4]}"
|
host="${args[4]}"
|
||||||
|
|
||||||
if [[ "${ip}" == "noip" ]]; then
|
if [[ "${ip}" == "noip" ]]; then
|
||||||
# Static host name
|
# Static host name
|
||||||
echo "dhcp-host=${mac},${host}" >> "${dhcpstaticconfig}"
|
echo "dhcp-host=${mac},${host}" >> "${dhcpstaticconfig}"
|
||||||
elif [[ "${host}" == "nohost" ]]; then
|
elif [[ "${host}" == "nohost" ]]; then
|
||||||
# Static IP
|
# Static IP
|
||||||
echo "dhcp-host=${mac},${ip}" >> "${dhcpstaticconfig}"
|
echo "dhcp-host=${mac},${ip}" >> "${dhcpstaticconfig}"
|
||||||
else
|
else
|
||||||
# Full info given
|
# Full info given
|
||||||
echo "dhcp-host=${mac},${ip},${host}" >> "${dhcpstaticconfig}"
|
echo "dhcp-host=${mac},${ip},${host}" >> "${dhcpstaticconfig}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveDHCPStaticAddress() {
|
RemoveDHCPStaticAddress() {
|
||||||
mac="${args[2]}"
|
mac="${args[2]}"
|
||||||
sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}"
|
sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}"
|
||||||
}
|
}
|
||||||
|
|
||||||
SetHostRecord() {
|
SetHostRecord() {
|
||||||
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
|
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
|
||||||
echo "Usage: pihole -a hostrecord <domain> [IPv4-address],[IPv6-address]
|
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'
|
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
|
Add a name to the DNS associated to an IPv4/IPv6 address
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
\"\" Empty: Remove host record
|
\"\" Empty: Remove host record
|
||||||
-h, --help Show this help dialog"
|
-h, --help Show this help dialog"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${args[3]}" ]]; then
|
if [[ -n "${args[3]}" ]]; then
|
||||||
change_setting "HOSTRECORD" "${args[2]},${args[3]}"
|
change_setting "HOSTRECORD" "${args[2]},${args[3]}"
|
||||||
echo -e " ${TICK} Setting host record for ${args[2]} to ${args[3]}"
|
echo -e " ${TICK} Setting host record for ${args[2]} to ${args[3]}"
|
||||||
else
|
else
|
||||||
change_setting "HOSTRECORD" ""
|
change_setting "HOSTRECORD" ""
|
||||||
echo -e " ${TICK} Removing host record"
|
echo -e " ${TICK} Removing host record"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ProcessDNSSettings
|
ProcessDNSSettings
|
||||||
|
|
||||||
# Restart dnsmasq to load new configuration
|
# Restart dnsmasq to load new configuration
|
||||||
RestartDNS
|
RestartDNS
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAdminEmail() {
|
SetAdminEmail() {
|
||||||
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
|
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
|
||||||
echo "Usage: pihole -a email <address>
|
echo "Usage: pihole -a email <address>
|
||||||
Example: 'pihole -a email admin@address.com'
|
Example: 'pihole -a email admin@address.com'
|
||||||
Set an administrative contact address for the Block Page
|
Set an administrative contact address for the Block Page
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
\"\" Empty: Remove admin contact
|
\"\" Empty: Remove admin contact
|
||||||
-h, --help Show this help dialog"
|
-h, --help Show this help dialog"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${args[2]}" ]]; then
|
if [[ -n "${args[2]}" ]]; then
|
||||||
change_setting "ADMIN_EMAIL" "${args[2]}"
|
change_setting "ADMIN_EMAIL" "${args[2]}"
|
||||||
echo -e " ${TICK} Setting admin contact to ${args[2]}"
|
echo -e " ${TICK} Setting admin contact to ${args[2]}"
|
||||||
else
|
else
|
||||||
change_setting "ADMIN_EMAIL" ""
|
change_setting "ADMIN_EMAIL" ""
|
||||||
echo -e " ${TICK} Removing admin contact"
|
echo -e " ${TICK} Removing admin contact"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
SetListeningMode() {
|
SetListeningMode() {
|
||||||
source "${setupVars}"
|
source "${setupVars}"
|
||||||
|
|
||||||
if [[ "$3" == "-h" ]] || [[ "$3" == "--help" ]]; then
|
if [[ "$3" == "-h" ]] || [[ "$3" == "--help" ]]; then
|
||||||
echo "Usage: pihole -a -i [interface]
|
echo "Usage: pihole -a -i [interface]
|
||||||
Example: 'pihole -a -i local'
|
Example: 'pihole -a -i local'
|
||||||
Specify dnsmasq's network interface listening behavior
|
Specify dnsmasq's network interface listening behavior
|
||||||
|
|
||||||
|
@ -472,74 +497,82 @@ Interfaces:
|
||||||
devices that are at most one hop away (local devices)
|
devices that are at most one hop away (local devices)
|
||||||
single Listen only on ${PIHOLE_INTERFACE} interface
|
single Listen only on ${PIHOLE_INTERFACE} interface
|
||||||
all Listen on all interfaces, permit all origins"
|
all Listen on all interfaces, permit all origins"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${args[2]}" == "all" ]]; then
|
if [[ "${args[2]}" == "all" ]]; then
|
||||||
echo -e " ${INFO} Listening on all interfaces, permiting all origins. Please use a firewall!"
|
echo -e " ${INFO} Listening on all interfaces, permiting all origins. Please use a firewall!"
|
||||||
change_setting "DNSMASQ_LISTENING" "all"
|
change_setting "DNSMASQ_LISTENING" "all"
|
||||||
elif [[ "${args[2]}" == "local" ]]; then
|
elif [[ "${args[2]}" == "local" ]]; then
|
||||||
echo -e " ${INFO} Listening on all interfaces, permiting origins from one hop away (LAN)"
|
echo -e " ${INFO} Listening on all interfaces, permiting origins from one hop away (LAN)"
|
||||||
change_setting "DNSMASQ_LISTENING" "local"
|
change_setting "DNSMASQ_LISTENING" "local"
|
||||||
else
|
else
|
||||||
echo -e " ${INFO} Listening only on interface ${PIHOLE_INTERFACE}"
|
echo -e " ${INFO} Listening only on interface ${PIHOLE_INTERFACE}"
|
||||||
change_setting "DNSMASQ_LISTENING" "single"
|
change_setting "DNSMASQ_LISTENING" "single"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Don't restart DNS server yet because other settings
|
# Don't restart DNS server yet because other settings
|
||||||
# will be applied afterwards if "-web" is set
|
# will be applied afterwards if "-web" is set
|
||||||
if [[ "${args[3]}" != "-web" ]]; then
|
if [[ "${args[3]}" != "-web" ]]; then
|
||||||
ProcessDNSSettings
|
ProcessDNSSettings
|
||||||
# Restart dnsmasq to load new configuration
|
# Restart dnsmasq to load new configuration
|
||||||
RestartDNS
|
RestartDNS
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
Teleporter() {
|
Teleporter() {
|
||||||
local datetimestamp=$(date "+%Y-%m-%d_%H-%M-%S")
|
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"
|
php /var/www/html/admin/scripts/pi-hole/php/teleporter.php > "pi-hole-teleporter_${datetimestamp}.zip"
|
||||||
}
|
}
|
||||||
|
|
||||||
audit()
|
audit()
|
||||||
{
|
{
|
||||||
echo "${args[2]}" >> /etc/pihole/auditlog.list
|
echo "${args[2]}" >> /etc/pihole/auditlog.list
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPrivacyLevel() {
|
||||||
|
# Set privacy level. Minimum is 0, maximum is 3
|
||||||
|
if [ "${args[2]}" -ge 0 ] && [ "${args[2]}" -le 3 ]; then
|
||||||
|
changeFTLsetting "PRIVACYLEVEL" "${args[2]}"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
args=("$@")
|
args=("$@")
|
||||||
|
|
||||||
case "${args[1]}" in
|
case "${args[1]}" in
|
||||||
"-p" | "password" ) SetWebPassword;;
|
"-p" | "password" ) SetWebPassword;;
|
||||||
"-c" | "celsius" ) unit="C"; SetTemperatureUnit;;
|
"-c" | "celsius" ) unit="C"; SetTemperatureUnit;;
|
||||||
"-f" | "fahrenheit" ) unit="F"; SetTemperatureUnit;;
|
"-f" | "fahrenheit" ) unit="F"; SetTemperatureUnit;;
|
||||||
"-k" | "kelvin" ) unit="K"; SetTemperatureUnit;;
|
"-k" | "kelvin" ) unit="K"; SetTemperatureUnit;;
|
||||||
"setdns" ) SetDNSServers;;
|
"setdns" ) SetDNSServers;;
|
||||||
"setexcludedomains" ) SetExcludeDomains;;
|
"setexcludedomains" ) SetExcludeDomains;;
|
||||||
"setexcludeclients" ) SetExcludeClients;;
|
"setexcludeclients" ) SetExcludeClients;;
|
||||||
"poweroff" ) Poweroff;;
|
"poweroff" ) Poweroff;;
|
||||||
"reboot" ) Reboot;;
|
"reboot" ) Reboot;;
|
||||||
"restartdns" ) RestartDNS;;
|
"restartdns" ) RestartDNS;;
|
||||||
"setquerylog" ) SetQueryLogOptions;;
|
"setquerylog" ) SetQueryLogOptions;;
|
||||||
"enabledhcp" ) EnableDHCP;;
|
"enabledhcp" ) EnableDHCP;;
|
||||||
"disabledhcp" ) DisableDHCP;;
|
"disabledhcp" ) DisableDHCP;;
|
||||||
"layout" ) SetWebUILayout;;
|
"layout" ) SetWebUILayout;;
|
||||||
"-h" | "--help" ) helpFunc;;
|
"-h" | "--help" ) helpFunc;;
|
||||||
"privacymode" ) SetPrivacyMode;;
|
"privacymode" ) SetPrivacyMode;;
|
||||||
"resolve" ) ResolutionSettings;;
|
"resolve" ) ResolutionSettings;;
|
||||||
"addstaticdhcp" ) AddDHCPStaticAddress;;
|
"addstaticdhcp" ) AddDHCPStaticAddress;;
|
||||||
"removestaticdhcp" ) RemoveDHCPStaticAddress;;
|
"removestaticdhcp" ) RemoveDHCPStaticAddress;;
|
||||||
"-r" | "hostrecord" ) SetHostRecord "$3";;
|
"-r" | "hostrecord" ) SetHostRecord "$3";;
|
||||||
"-e" | "email" ) SetAdminEmail "$3";;
|
"-e" | "email" ) SetAdminEmail "$3";;
|
||||||
"-i" | "interface" ) SetListeningMode "$@";;
|
"-i" | "interface" ) SetListeningMode "$@";;
|
||||||
"-t" | "teleporter" ) Teleporter;;
|
"-t" | "teleporter" ) Teleporter;;
|
||||||
"adlist" ) CustomizeAdLists;;
|
"adlist" ) CustomizeAdLists;;
|
||||||
"audit" ) audit;;
|
"audit" ) audit;;
|
||||||
* ) helpFunc;;
|
"-l" | "privacylevel" ) SetPrivacyLevel;;
|
||||||
esac
|
* ) helpFunc;;
|
||||||
|
esac
|
||||||
|
|
||||||
shift
|
shift
|
||||||
|
|
||||||
if [[ $# = 0 ]]; then
|
if [[ $# = 0 ]]; then
|
||||||
helpFunc
|
helpFunc
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
28
advanced/Scripts/wildcard_regex_converter.sh
Normal file
28
advanced/Scripts/wildcard_regex_converter.sh
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
|
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
# Network-wide ad blocking via your own hardware.
|
||||||
|
#
|
||||||
|
# Provides an automated migration subroutine to convert Pi-hole v3.x wildcard domains to Pi-hole v4.x regex filters
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
# regexFile set in gravity.sh
|
||||||
|
|
||||||
|
wildcardFile="/etc/dnsmasq.d/03-pihole-wildcard.conf"
|
||||||
|
|
||||||
|
convert_wildcard_to_regex() {
|
||||||
|
if [ ! -f "${wildcardFile}" ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
local addrlines domains uniquedomains
|
||||||
|
# Obtain wildcard domains from old file
|
||||||
|
addrlines="$(grep -oE "/.*/" ${wildcardFile})"
|
||||||
|
# Strip "/" from domain names and convert "." to regex-compatible "\."
|
||||||
|
domains="$(sed 's/\///g;s/\./\\./g' <<< "${addrlines}")"
|
||||||
|
# Remove repeated domains (may have been inserted two times due to A and AAAA blocking)
|
||||||
|
uniquedomains="$(uniq <<< "${domains}")"
|
||||||
|
# Automatically generate regex filters and remove old wildcards file
|
||||||
|
awk '{print "(^|\\.)"$0"$"}' <<< "${uniquedomains}" >> "${regexFile:?}" && rm "${wildcardFile}"
|
||||||
|
}
|
84
advanced/Templates/pihole-FTL.conf
Normal file
84
advanced/Templates/pihole-FTL.conf
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
### This file contains parameters for FTL behavior.
|
||||||
|
### At install, all parameters are commented out. The user can select desired options.
|
||||||
|
### Options shown are the default configuration. No modification is needed for most
|
||||||
|
### installations.
|
||||||
|
### Visit https://docs.pi-hole.net/ftldns/configfile/ for more detailed parameter explanations
|
||||||
|
|
||||||
|
## Socket Listening
|
||||||
|
## Listen only for local socket connections or permit all connections
|
||||||
|
## Options: localonly, all
|
||||||
|
#SOCKET_LISTENING=localonly
|
||||||
|
|
||||||
|
## Query Display
|
||||||
|
## Display all queries? Set to no to hide query display
|
||||||
|
## Options: yes, no
|
||||||
|
#QUERY_DISPLAY=yes
|
||||||
|
|
||||||
|
## AAA Query Analysis
|
||||||
|
## Allow FTL to analyze AAAA queries from pihole.log?
|
||||||
|
## Options: yes, no
|
||||||
|
#AAAA_QUERY_ANALYSIS=yes
|
||||||
|
|
||||||
|
## Resolve IPv6
|
||||||
|
## Should FTL try to resolve IPv6 addresses to host names?
|
||||||
|
## Options: yes, no
|
||||||
|
#RESOLVE_IPV6=yes
|
||||||
|
|
||||||
|
## Resolve IPv4
|
||||||
|
## Should FTL try to resolve IPv4 addresses to host names?
|
||||||
|
## Options: yes, no
|
||||||
|
#RESOLVE_IPV4=yes
|
||||||
|
|
||||||
|
## Max Database Days
|
||||||
|
## How long should queries be stored in the database (days)?
|
||||||
|
## Setting this to 0 disables the database
|
||||||
|
## See: https://docs.pi-hole.net/ftldns/database/
|
||||||
|
## Options: number of days
|
||||||
|
#MAXDBDAYS=365
|
||||||
|
|
||||||
|
## Database Interval
|
||||||
|
## How often do we store queries in FTL's database (minutes)?
|
||||||
|
## See: https://docs.pi-hole.net/ftldns/database/
|
||||||
|
## Options: number of minutes
|
||||||
|
#DBINTERVAL=1.0
|
||||||
|
|
||||||
|
## Database File
|
||||||
|
## Specify path and filename of FTL's SQLite3 long-term database.
|
||||||
|
## Setting this to DBFILE= disables the database altogether
|
||||||
|
## See: https://docs.pi-hole.net/ftldns/database/
|
||||||
|
## Option: path to db file
|
||||||
|
#DBFILE=/etc/pihole/pihole-FTL.db
|
||||||
|
|
||||||
|
## Max Log Age
|
||||||
|
## Up to how many hours of queries should be imported from the database and logs (hours)?
|
||||||
|
## Maximum is 744 (31 days)
|
||||||
|
## Options: number of days
|
||||||
|
#MAXLOGAGE=24.0
|
||||||
|
|
||||||
|
## FTL Port
|
||||||
|
## On which port should FTL be listening?
|
||||||
|
## Options: tcp port
|
||||||
|
#FTLPORT=4711
|
||||||
|
|
||||||
|
## Privacy Level
|
||||||
|
## Which privacy level is used?
|
||||||
|
## See: https://docs.pi-hole.net/ftldns/privacylevels/
|
||||||
|
## Options: 0, 1, 2, 3
|
||||||
|
#PRIVACYLEVEL=0
|
||||||
|
|
||||||
|
## Ignore Localhost
|
||||||
|
## Should FTL ignore queries coming from the local machine?
|
||||||
|
## Options: yes, no
|
||||||
|
#IGNORE_LOCALHOST=no
|
||||||
|
|
||||||
|
## Blocking Mode
|
||||||
|
## How should FTL reply to blocked queries?
|
||||||
|
## See: https://docs.pi-hole.net/ftldns/blockingmode/
|
||||||
|
## Options: NULL, IP-AAAA-NODATA, IP, NXDOMAIN
|
||||||
|
#BLOCKINGMODE=NULL
|
||||||
|
|
||||||
|
## Regex Debug Mode
|
||||||
|
## Controls if FTLDNS should print extended details about regex matching into pihole-FTL.log.
|
||||||
|
## See: https://docs.pi-hole.net/ftldns/regex/overview/
|
||||||
|
## Options: true, false
|
||||||
|
#REGEX_DEBUGMODE=false
|
|
@ -20,6 +20,7 @@ is_running() {
|
||||||
ps "$(get_pid)" > /dev/null 2>&1
|
ps "$(get_pid)" > /dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Start the service
|
# Start the service
|
||||||
start() {
|
start() {
|
||||||
if is_running; then
|
if is_running; then
|
||||||
|
@ -29,9 +30,12 @@ start() {
|
||||||
mkdir -p /var/run/pihole
|
mkdir -p /var/run/pihole
|
||||||
mkdir -p /var/log/pihole
|
mkdir -p /var/log/pihole
|
||||||
chown pihole:pihole /var/run/pihole /var/log/pihole
|
chown pihole:pihole /var/run/pihole /var/log/pihole
|
||||||
rm /var/run/pihole/FTL.sock
|
rm /var/run/pihole/FTL.sock 2> /dev/null
|
||||||
chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /etc/pihole
|
chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port
|
||||||
|
chown pihole:pihole /etc/pihole /etc/pihole/dhcp.leases /var/log/pihole.log
|
||||||
chmod 0644 /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole.log
|
chmod 0644 /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole.log
|
||||||
|
setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN+eip "$(which pihole-FTL)"
|
||||||
|
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.piholeFTL
|
||||||
su -s /bin/sh -c "/usr/bin/pihole-FTL" "$FTLUSER"
|
su -s /bin/sh -c "/usr/bin/pihole-FTL" "$FTLUSER"
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
@ -40,6 +44,7 @@ start() {
|
||||||
# Stop the service
|
# Stop the service
|
||||||
stop() {
|
stop() {
|
||||||
if is_running; then
|
if is_running; then
|
||||||
|
/sbin/resolvconf -d lo.piholeFTL
|
||||||
kill "$(get_pid)"
|
kill "$(get_pid)"
|
||||||
for i in {1..5}; do
|
for i in {1..5}; do
|
||||||
if ! is_running; then
|
if ! is_running; then
|
||||||
|
@ -64,13 +69,25 @@ stop() {
|
||||||
echo
|
echo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Indicate the service status
|
||||||
|
status() {
|
||||||
|
if is_running; then
|
||||||
|
echo "[ ok ] pihole-FTL is running"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "[ ] pihole-FTL is not running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
### main logic ###
|
### main logic ###
|
||||||
case "$1" in
|
case "$1" in
|
||||||
stop)
|
stop)
|
||||||
stop
|
stop
|
||||||
;;
|
;;
|
||||||
status)
|
status)
|
||||||
status pihole-FTL
|
status
|
||||||
;;
|
;;
|
||||||
start|restart|reload|condrestart)
|
start|restart|reload|condrestart)
|
||||||
stop
|
stop
|
|
@ -1,11 +1,79 @@
|
||||||
_pihole() {
|
_pihole() {
|
||||||
local cur prev opts
|
local cur prev opts opts_admin opts_checkout opts_chronometer opts_debug opts_interface opts_logging opts_privacy opts_query opts_update opts_version
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
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"
|
prev2="${COMP_WORDS[COMP_CWORD-2]}"
|
||||||
|
|
||||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
case "${prev}" in
|
||||||
|
"pihole")
|
||||||
|
opts="admin blacklist checkout chronometer debug disable enable flush help logging query reconfigure regex restartdns status tail uninstall updateGravity updatePihole version wildcard whitelist"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"whitelist"|"blacklist"|"wildcard"|"regex")
|
||||||
|
opts_lists="\--delmode \--noreload \--quiet \--list \--nuke"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_lists}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"admin")
|
||||||
|
opts_admin="celsius email fahrenheit hostrecord interface kelvin password privacylevel"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_admin}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"checkout")
|
||||||
|
opts_checkout="core ftl web master dev"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_checkout}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"chronometer")
|
||||||
|
opts_chronometer="\--exit \--json \--refresh"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_chronometer}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"debug")
|
||||||
|
opts_debug="-a"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_debug}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"logging")
|
||||||
|
opts_logging="on off 'off noflush'"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_logging}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"query")
|
||||||
|
opts_query="-adlist -all -exact"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_query}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"updatePihole"|"-up")
|
||||||
|
opts_update="--check-only"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_update}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"version")
|
||||||
|
opts_version="\--admin \--current \--ftl \--hash \--latest \--pihole"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_version}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"interface")
|
||||||
|
if ( [[ "$prev2" == "admin" ]] || [[ "$prev2" == "-a" ]] ); then
|
||||||
|
opts_interface="$(cat /proc/net/dev | cut -d: -s -f1)"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_interface}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"privacylevel")
|
||||||
|
if ( [[ "$prev2" == "admin" ]] || [[ "$prev2" == "-a" ]] ); then
|
||||||
|
opts_privacy="0 1 2 3"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_privacy}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"core"|"admin"|"ftl")
|
||||||
|
if [[ "$prev2" == "checkout" ]]; then
|
||||||
|
opts_checkout="master dev"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_checkout}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
complete -F _pihole pihole
|
complete -F _pihole pihole
|
||||||
|
|
|
@ -64,7 +64,7 @@ if ($serverName === "pi.hole") {
|
||||||
<html><head>
|
<html><head>
|
||||||
$viewPort
|
$viewPort
|
||||||
<link rel='stylesheet' href='/pihole/blockingpage.css' type='text/css'/>
|
<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>
|
</head><body id='splashpage'><img src='/admin/img/logo.svg'/><br/>Pi-<b>hole</b>: Your black hole for Internet advertisements<br><a href='/admin'>Did you mean to go to the admin panel?</a></body></html>
|
||||||
";
|
";
|
||||||
|
|
||||||
// Set splash/landing page based off presence of $landPage
|
// Set splash/landing page based off presence of $landPage
|
||||||
|
@ -102,8 +102,10 @@ if ($serverName === "pi.hole") {
|
||||||
$bpAskAdmin = !empty($svEmail) ? '<a href="mailto:'.$svEmail.'?subject=Site Blocked: '.$serverName.'"></a>' : "<span/>";
|
$bpAskAdmin = !empty($svEmail) ? '<a href="mailto:'.$svEmail.'?subject=Site Blocked: '.$serverName.'"></a>' : "<span/>";
|
||||||
|
|
||||||
// Determine if at least one block list has been generated
|
// Determine if at least one block list has been generated
|
||||||
if (empty(glob("/etc/pihole/list.0.*.domains")))
|
$blocklistglob = glob("/etc/pihole/list.0.*.domains");
|
||||||
|
if ($blocklistglob === array()) {
|
||||||
die("[ERROR] There are no domain lists generated lists within <code>/etc/pihole/</code>! Please update gravity by running <code>pihole -g</code>, or repair Pi-hole using <code>pihole -r</code>.");
|
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
|
// Set location of adlists file
|
||||||
if (is_file("/etc/pihole/adlists.list")) {
|
if (is_file("/etc/pihole/adlists.list")) {
|
||||||
|
@ -327,6 +329,7 @@ setHeader();
|
||||||
setTimeout(function(){window.location.reload(1);}, 10000);
|
setTimeout(function(){window.location.reload(1);}, 10000);
|
||||||
$("#bpOutput").removeClass("add");
|
$("#bpOutput").removeClass("add");
|
||||||
$("#bpOutput").addClass("success");
|
$("#bpOutput").addClass("success");
|
||||||
|
$("#bpOutput").html("");
|
||||||
} else {
|
} else {
|
||||||
$("#bpOutput").removeClass("add");
|
$("#bpOutput").removeClass("add");
|
||||||
$("#bpOutput").addClass("error");
|
$("#bpOutput").addClass("error");
|
||||||
|
@ -336,6 +339,7 @@ setHeader();
|
||||||
error: function(jqXHR, exception) {
|
error: function(jqXHR, exception) {
|
||||||
$("#bpOutput").removeClass("add");
|
$("#bpOutput").removeClass("add");
|
||||||
$("#bpOutput").addClass("exception");
|
$("#bpOutput").addClass("exception");
|
||||||
|
$("#bpOutput").html("");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,29 +11,29 @@
|
||||||
source "/opt/pihole/COL_TABLE"
|
source "/opt/pihole/COL_TABLE"
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
read -rp " ${QST} Are you sure you would like to remove ${COL_WHITE}Pi-hole${COL_NC}? [y/N] " yn
|
read -rp " ${QST} Are you sure you would like to remove ${COL_WHITE}Pi-hole${COL_NC}? [y/N] " yn
|
||||||
case ${yn} in
|
case ${yn} in
|
||||||
[Yy]* ) break;;
|
[Yy]* ) break;;
|
||||||
[Nn]* ) echo -e "\n ${COL_LIGHT_GREEN}Uninstall has been cancelled${COL_NC}"; exit 0;;
|
[Nn]* ) echo -e "${OVER} ${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;;
|
* ) echo -e "${OVER} ${COL_LIGHT_GREEN}Uninstall has been cancelled${COL_NC}"; exit 0;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# Must be root to uninstall
|
# Must be root to uninstall
|
||||||
str="Root user check"
|
str="Root user check"
|
||||||
if [[ ${EUID} -eq 0 ]]; then
|
if [[ ${EUID} -eq 0 ]]; then
|
||||||
echo -e " ${TICK} ${str}"
|
echo -e " ${TICK} ${str}"
|
||||||
else
|
else
|
||||||
# Check if sudo is actually installed
|
# Check if sudo is actually installed
|
||||||
# If it isn't, exit because the uninstall can not complete
|
# If it isn't, exit because the uninstall can not complete
|
||||||
if [ -x "$(command -v sudo)" ]; then
|
if [ -x "$(command -v sudo)" ]; then
|
||||||
export SUDO="sudo"
|
export SUDO="sudo"
|
||||||
else
|
else
|
||||||
echo -e " ${CROSS} ${str}
|
echo -e " ${CROSS} ${str}
|
||||||
Script called with non-root privileges
|
Script called with non-root privileges
|
||||||
The Pi-hole requires elevated privleges to uninstall"
|
The Pi-hole requires elevated privleges to uninstall"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||||
|
@ -46,178 +46,172 @@ source "${setupVars}"
|
||||||
distro_check
|
distro_check
|
||||||
|
|
||||||
# Install packages used by the Pi-hole
|
# Install packages used by the Pi-hole
|
||||||
if [[ "${INSTALL_WEB}" == true ]]; then
|
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}")
|
||||||
# Install the Web dependencies
|
if [[ "${INSTALL_WEB_SERVER}" == true ]]; then
|
||||||
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}" "${PIHOLE_WEB_DEPS[@]}")
|
# Install the Web dependencies
|
||||||
# Otherwise,
|
DEPS+=("${PIHOLE_WEB_DEPS[@]}")
|
||||||
else
|
|
||||||
# just install the Core dependencies
|
|
||||||
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}")
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Compatability
|
# Compatability
|
||||||
if [ -x "$(command -v rpm)" ]; then
|
if [ -x "$(command -v apt-get)" ]; then
|
||||||
# Fedora Family
|
# Debian Family
|
||||||
PKG_REMOVE="${PKG_MANAGER} remove -y"
|
PKG_REMOVE="${PKG_MANAGER} -y remove --purge"
|
||||||
package_check() {
|
package_check() {
|
||||||
rpm -qa | grep ^$1- > /dev/null
|
dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -c "ok installed"
|
||||||
}
|
}
|
||||||
package_cleanup() {
|
elif [ -x "$(command -v rpm)" ]; then
|
||||||
${SUDO} ${PKG_MANAGER} -y autoremove
|
# Fedora Family
|
||||||
}
|
PKG_REMOVE="${PKG_MANAGER} remove -y"
|
||||||
elif [ -x "$(command -v apt-get)" ]; then
|
package_check() {
|
||||||
# Debian Family
|
rpm -qa | grep "^$1-" > /dev/null
|
||||||
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
|
else
|
||||||
echo -e " ${CROSS} OS distribution not supported"
|
echo -e " ${CROSS} OS distribution not supported"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
removeAndPurge() {
|
removeAndPurge() {
|
||||||
# Purge dependencies
|
# Purge dependencies
|
||||||
echo ""
|
echo ""
|
||||||
for i in "${DEPS[@]}"; do
|
for i in "${DEPS[@]}"; do
|
||||||
package_check ${i} > /dev/null
|
if package_check "${i}" > /dev/null; then
|
||||||
if [[ "$?" -eq 0 ]]; then
|
while true; do
|
||||||
while true; do
|
read -rp " ${QST} Do you wish to remove ${COL_WHITE}${i}${COL_NC} from your system? [Y/N] " yn
|
||||||
read -rp " ${QST} Do you wish to remove ${COL_WHITE}${i}${COL_NC} from your system? [Y/N] " yn
|
case ${yn} in
|
||||||
case ${yn} in
|
[Yy]* )
|
||||||
[Yy]* )
|
echo -ne " ${INFO} Removing ${i}...";
|
||||||
echo -ne " ${INFO} Removing ${i}...";
|
${SUDO} "${PKG_REMOVE} ${i}" &> /dev/null;
|
||||||
${SUDO} ${PKG_REMOVE} "${i}" &> /dev/null;
|
echo -e "${OVER} ${INFO} Removed ${i}";
|
||||||
echo -e "${OVER} ${INFO} Removed ${i}";
|
break;;
|
||||||
break;;
|
[Nn]* ) echo -e " ${INFO} Skipped ${i}"; break;;
|
||||||
[Nn]* ) echo -e " ${INFO} Skipped ${i}"; break;;
|
esac
|
||||||
esac
|
done
|
||||||
done
|
else
|
||||||
else
|
echo -e " ${INFO} Package ${i} not installed"
|
||||||
echo -e " ${INFO} Package ${i} not installed"
|
fi
|
||||||
fi
|
done
|
||||||
done
|
|
||||||
|
|
||||||
# Remove dnsmasq config files
|
# Remove dnsmasq config files
|
||||||
${SUDO} rm -f /etc/dnsmasq.conf /etc/dnsmasq.conf.orig /etc/dnsmasq.d/01-pihole.conf &> /dev/null
|
${SUDO} rm -f /etc/dnsmasq.conf /etc/dnsmasq.conf.orig /etc/dnsmasq.d/*-pihole*.conf &> /dev/null
|
||||||
echo -e " ${TICK} Removing dnsmasq config files"
|
echo -e " ${TICK} Removing dnsmasq config files"
|
||||||
|
|
||||||
# Take care of any additional package cleaning
|
# Call removeNoPurge to remove Pi-hole specific files
|
||||||
echo -ne " ${INFO} Removing & cleaning remaining dependencies..."
|
removeNoPurge
|
||||||
package_cleanup &> /dev/null
|
|
||||||
echo -e "${OVER} ${TICK} Removed & cleaned up remaining dependencies"
|
|
||||||
|
|
||||||
# Call removeNoPurge to remove Pi-hole specific files
|
|
||||||
removeNoPurge
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeNoPurge() {
|
removeNoPurge() {
|
||||||
# Only web directories/files that are created by Pi-hole should be removed
|
# Only web directories/files that are created by Pi-hole should be removed
|
||||||
echo -ne " ${INFO} Removing Web Interface..."
|
echo -ne " ${INFO} Removing Web Interface..."
|
||||||
${SUDO} rm -rf /var/www/html/admin &> /dev/null
|
${SUDO} rm -rf /var/www/html/admin &> /dev/null
|
||||||
${SUDO} rm -rf /var/www/html/pihole &> /dev/null
|
${SUDO} rm -rf /var/www/html/pihole &> /dev/null
|
||||||
${SUDO} rm -f /var/www/html/index.lighttpd.orig &> /dev/null
|
${SUDO} rm -f /var/www/html/index.lighttpd.orig &> /dev/null
|
||||||
|
|
||||||
# If the web directory is empty after removing these files, then the parent html folder can be removed.
|
# 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 [ -d "/var/www/html" ]; then
|
||||||
if [[ ! "$(ls -A /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
|
||||||
fi
|
fi
|
||||||
echo -e "${OVER} ${TICK} Removed Web Interface"
|
echo -e "${OVER} ${TICK} Removed Web Interface"
|
||||||
|
|
||||||
# Attempt to preserve backwards compatibility with older versions
|
# Attempt to preserve backwards compatibility with older versions
|
||||||
# to guarantee no additional changes were made to /etc/crontab after
|
# to guarantee no additional changes were made to /etc/crontab after
|
||||||
# the installation of pihole, /etc/crontab.pihole should be permanently
|
# the installation of pihole, /etc/crontab.pihole should be permanently
|
||||||
# preserved.
|
# preserved.
|
||||||
if [[ -f /etc/crontab.orig ]]; then
|
if [[ -f /etc/crontab.orig ]]; then
|
||||||
${SUDO} mv /etc/crontab /etc/crontab.pihole
|
${SUDO} mv /etc/crontab /etc/crontab.pihole
|
||||||
${SUDO} mv /etc/crontab.orig /etc/crontab
|
${SUDO} mv /etc/crontab.orig /etc/crontab
|
||||||
${SUDO} service cron restart
|
${SUDO} service cron restart
|
||||||
echo -e " ${TICK} Restored the default system cron"
|
echo -e " ${TICK} Restored the default system cron"
|
||||||
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"
|
|
||||||
fi
|
|
||||||
|
|
||||||
package_check lighttpd > /dev/null
|
|
||||||
if [[ $? -eq 1 ]]; then
|
|
||||||
${SUDO} rm -rf /etc/lighttpd/ &> /dev/null
|
|
||||||
echo -e " ${TICK} Removed lighttpd"
|
|
||||||
else
|
|
||||||
if [ -f /etc/lighttpd/lighttpd.conf.orig ]; then
|
|
||||||
${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
|
fi
|
||||||
|
|
||||||
${SUDO} rm -f /etc/init.d/pihole-FTL
|
# Attempt to preserve backwards compatibility with older versions
|
||||||
${SUDO} rm -f /usr/bin/pihole-FTL
|
if [[ -f /etc/cron.d/pihole ]];then
|
||||||
echo -e "${OVER} ${TICK} Removed pihole-FTL"
|
${SUDO} rm -f /etc/cron.d/pihole &> /dev/null
|
||||||
fi
|
echo -e " ${TICK} Removed /etc/cron.d/pihole"
|
||||||
|
|
||||||
# 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
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "\n We're sorry to see you go, but thanks for checking out Pi-hole!
|
package_check lighttpd > /dev/null
|
||||||
If you need help, reach out to us on Github, Discourse, Reddit or Twitter
|
if [[ $? -eq 1 ]]; then
|
||||||
Reinstall at any time: ${COL_WHITE}curl -sSL https://install.pi-hole.net | bash${COL_NC}
|
${SUDO} rm -rf /etc/lighttpd/ &> /dev/null
|
||||||
|
echo -e " ${TICK} Removed lighttpd"
|
||||||
|
else
|
||||||
|
if [ -f /etc/lighttpd/lighttpd.conf.orig ]; then
|
||||||
|
${SUDO} mv /etc/lighttpd/lighttpd.conf.orig /etc/lighttpd/lighttpd.conf
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
${COL_LIGHT_RED}Please reset the DNS on your router/clients to restore internet connectivity
|
${SUDO} rm -f /etc/dnsmasq.d/adList.conf &> /dev/null
|
||||||
${COL_LIGHT_GREEN}Uninstallation Complete! ${COL_NC}"
|
${SUDO} rm -f /etc/dnsmasq.d/01-pihole.conf &> /dev/null
|
||||||
|
${SUDO} rm -rf /var/log/*pihole* &> /dev/null
|
||||||
|
${SUDO} rm -rf /etc/pihole/ &> /dev/null
|
||||||
|
${SUDO} rm -rf /etc/.pihole/ &> /dev/null
|
||||||
|
${SUDO} rm -rf /opt/pihole/ &> /dev/null
|
||||||
|
${SUDO} rm -f /usr/local/bin/pihole &> /dev/null
|
||||||
|
${SUDO} rm -f /etc/bash_completion.d/pihole &> /dev/null
|
||||||
|
${SUDO} rm -f /etc/sudoers.d/pihole &> /dev/null
|
||||||
|
echo -e " ${TICK} Removed config files"
|
||||||
|
|
||||||
|
# Restore Resolved
|
||||||
|
if [[ -e /etc/systemd/resolved.conf.orig ]]; then
|
||||||
|
${SUDO} cp /etc/systemd/resolved.conf.orig /etc/systemd/resolved.conf
|
||||||
|
systemctl reload-or-restart systemd-resolved
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove FTL
|
||||||
|
if command -v pihole-FTL &> /dev/null; then
|
||||||
|
echo -ne " ${INFO} Removing pihole-FTL..."
|
||||||
|
if [[ -x "$(command -v systemctl)" ]]; then
|
||||||
|
systemctl stop pihole-FTL
|
||||||
|
else
|
||||||
|
service pihole-FTL stop
|
||||||
|
fi
|
||||||
|
${SUDO} rm -f /etc/init.d/pihole-FTL
|
||||||
|
${SUDO} rm -f /usr/bin/pihole-FTL
|
||||||
|
echo -e "${OVER} ${TICK} Removed pihole-FTL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If the pihole manpage exists, then delete and rebuild man-db
|
||||||
|
if [[ -f /usr/local/share/man/man8/pihole.8 ]]; then
|
||||||
|
${SUDO} rm -f /usr/local/share/man/man8/pihole.8 /usr/local/share/man/man8/pihole-FTL.8 /usr/local/share/man/man5/pihole-FTL.conf.5
|
||||||
|
${SUDO} mandb -q &>/dev/null
|
||||||
|
echo -e " ${TICK} Removed pihole man page"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If the pihole user exists, then remove
|
||||||
|
if id "pihole" &> /dev/null; then
|
||||||
|
if ${SUDO} userdel -r pihole 2> /dev/null; then
|
||||||
|
echo -e " ${TICK} Removed 'pihole' user"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} Unable to remove 'pihole' user"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
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}"
|
||||||
}
|
}
|
||||||
|
|
||||||
######### SCRIPT ###########
|
######### SCRIPT ###########
|
||||||
if command -v vcgencmd &> /dev/null; then
|
if command -v vcgencmd &> /dev/null; then
|
||||||
echo -e " ${INFO} All dependencies are safe to remove on Raspbian"
|
echo -e " ${INFO} All dependencies are safe to remove on Raspbian"
|
||||||
else
|
else
|
||||||
echo -e " ${INFO} Be sure to confirm if any dependencies should not be removed"
|
echo -e " ${INFO} Be sure to confirm if any dependencies should not be removed"
|
||||||
fi
|
fi
|
||||||
while true; do
|
while true; do
|
||||||
echo -e " ${INFO} ${COL_YELLOW}The following dependencies may have been added by the Pi-hole install:"
|
echo -e " ${INFO} ${COL_YELLOW}The following dependencies may have been added by the Pi-hole install:"
|
||||||
echo -n " "
|
echo -n " "
|
||||||
for i in "${DEPS[@]}"; do
|
for i in "${DEPS[@]}"; do
|
||||||
echo -n "${i} "
|
echo -n "${i} "
|
||||||
done
|
done
|
||||||
echo "${COL_NC}"
|
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
|
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
|
case ${yn} in
|
||||||
[Yy]* ) removeAndPurge; break;;
|
[Yy]* ) removeAndPurge; break;;
|
||||||
[Nn]* ) removeNoPurge; break;;
|
[Nn]* ) removeNoPurge; break;;
|
||||||
* ) removeAndPurge; break;;
|
* ) removeAndPurge; break;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
139
gravity.sh
139
gravity.sh
|
@ -15,20 +15,20 @@ export LC_ALL=C
|
||||||
|
|
||||||
coltable="/opt/pihole/COL_TABLE"
|
coltable="/opt/pihole/COL_TABLE"
|
||||||
source "${coltable}"
|
source "${coltable}"
|
||||||
|
regexconverter="/opt/pihole/wildcard_regex_converter.sh"
|
||||||
|
source "${regexconverter}"
|
||||||
|
|
||||||
basename="pihole"
|
basename="pihole"
|
||||||
PIHOLE_COMMAND="/usr/local/bin/${basename}"
|
PIHOLE_COMMAND="/usr/local/bin/${basename}"
|
||||||
|
|
||||||
piholeDir="/etc/${basename}"
|
piholeDir="/etc/${basename}"
|
||||||
piholeRepo="/etc/.${basename}"
|
|
||||||
|
|
||||||
adListFile="${piholeDir}/adlists.list"
|
adListFile="${piholeDir}/adlists.list"
|
||||||
adListDefault="${piholeDir}/adlists.default"
|
adListDefault="${piholeDir}/adlists.default"
|
||||||
adListRepoDefault="${piholeRepo}/adlists.default"
|
|
||||||
|
|
||||||
whitelistFile="${piholeDir}/whitelist.txt"
|
whitelistFile="${piholeDir}/whitelist.txt"
|
||||||
blacklistFile="${piholeDir}/blacklist.txt"
|
blacklistFile="${piholeDir}/blacklist.txt"
|
||||||
wildcardFile="/etc/dnsmasq.d/03-pihole-wildcard.conf"
|
regexFile="${piholeDir}/regex.list"
|
||||||
|
|
||||||
adList="${piholeDir}/gravity.list"
|
adList="${piholeDir}/gravity.list"
|
||||||
blackList="${piholeDir}/black.list"
|
blackList="${piholeDir}/black.list"
|
||||||
|
@ -44,6 +44,10 @@ preEventHorizon="list.preEventHorizon"
|
||||||
|
|
||||||
skipDownload="false"
|
skipDownload="false"
|
||||||
|
|
||||||
|
resolver="pihole-FTL"
|
||||||
|
|
||||||
|
haveSourceUrls=true
|
||||||
|
|
||||||
# Source setupVars from install script
|
# Source setupVars from install script
|
||||||
setupVars="${piholeDir}/setupVars.conf"
|
setupVars="${piholeDir}/setupVars.conf"
|
||||||
if [[ -f "${setupVars}" ]];then
|
if [[ -f "${setupVars}" ]];then
|
||||||
|
@ -104,7 +108,7 @@ gravity_CheckDNSResolutionAvailable() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Determine error output message
|
# Determine error output message
|
||||||
if pidof dnsmasq &> /dev/null; then
|
if pidof ${resolver} &> /dev/null; then
|
||||||
echo -e " ${CROSS} DNS resolution is currently unavailable"
|
echo -e " ${CROSS} DNS resolution is currently unavailable"
|
||||||
else
|
else
|
||||||
echo -e " ${CROSS} DNS service is not running"
|
echo -e " ${CROSS} DNS service is not running"
|
||||||
|
@ -129,20 +133,12 @@ gravity_CheckDNSResolutionAvailable() {
|
||||||
gravity_GetBlocklistUrls() {
|
gravity_GetBlocklistUrls() {
|
||||||
echo -e " ${INFO} ${COL_BOLD}Neutrino emissions detected${COL_NC}..."
|
echo -e " ${INFO} ${COL_BOLD}Neutrino emissions detected${COL_NC}..."
|
||||||
|
|
||||||
# Determine if adlists file needs handling
|
if [[ -f "${adListDefault}" ]] && [[ -f "${adListFile}" ]]; then
|
||||||
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
|
# Remove superceded $adListDefault file
|
||||||
rm "${adListDefault}" 2> /dev/null || \
|
rm "${adListDefault}" 2> /dev/null || \
|
||||||
echo -e " ${CROSS} Unable to remove ${adListDefault}"
|
echo -e " ${CROSS} Unable to remove ${adListDefault}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local str="Pulling blocklist source list into range"
|
|
||||||
echo -ne " ${INFO} ${str}..."
|
|
||||||
|
|
||||||
# Retrieve source URLs from $adListFile
|
# Retrieve source URLs from $adListFile
|
||||||
# Logic: Remove comments and empty lines
|
# Logic: Remove comments and empty lines
|
||||||
mapfile -t sources <<< "$(grep -v -E "^(#|$)" "${adListFile}" 2> /dev/null)"
|
mapfile -t sources <<< "$(grep -v -E "^(#|$)" "${adListFile}" 2> /dev/null)"
|
||||||
|
@ -158,11 +154,15 @@ gravity_GetBlocklistUrls() {
|
||||||
}' <<< "$(printf '%s\n' "${sources[@]}")" 2> /dev/null
|
}' <<< "$(printf '%s\n' "${sources[@]}")" 2> /dev/null
|
||||||
)"
|
)"
|
||||||
|
|
||||||
|
local str="Pulling blocklist source list into range"
|
||||||
|
|
||||||
if [[ -n "${sources[*]}" ]] && [[ -n "${sourceDomains[*]}" ]]; then
|
if [[ -n "${sources[*]}" ]] && [[ -n "${sourceDomains[*]}" ]]; then
|
||||||
echo -e "${OVER} ${TICK} ${str}"
|
echo -e "${OVER} ${TICK} ${str}"
|
||||||
else
|
else
|
||||||
echo -e "${OVER} ${CROSS} ${str}"
|
echo -e "${OVER} ${CROSS} ${str}"
|
||||||
gravity_Cleanup "error"
|
echo -e " ${INFO} No source list found, or it is empty"
|
||||||
|
echo ""
|
||||||
|
haveSourceUrls=false
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,8 +220,15 @@ gravity_DownloadBlocklistFromUrl() {
|
||||||
httpCode=$(curl -s -L ${cmd_ext} ${heisenbergCompensator} -w "%{http_code}" -A "${agent}" "${url}" -o "${patternBuffer}" 2> /dev/null)
|
httpCode=$(curl -s -L ${cmd_ext} ${heisenbergCompensator} -w "%{http_code}" -A "${agent}" "${url}" -o "${patternBuffer}" 2> /dev/null)
|
||||||
|
|
||||||
case $url in
|
case $url in
|
||||||
|
# Did we "download" a local file?
|
||||||
|
"file"*)
|
||||||
|
if [[ -s "${patternBuffer}" ]]; then
|
||||||
|
echo -e "${OVER} ${TICK} ${str} Retrieval successful"; success=true
|
||||||
|
else
|
||||||
|
echo -e "${OVER} ${CROSS} ${str} Not found / empty list"
|
||||||
|
fi;;
|
||||||
# Did we "download" a remote file?
|
# Did we "download" a remote file?
|
||||||
"http"*)
|
*)
|
||||||
# Determine "Status:" output based on HTTP response
|
# Determine "Status:" output based on HTTP response
|
||||||
case "${httpCode}" in
|
case "${httpCode}" in
|
||||||
"200") echo -e "${OVER} ${TICK} ${str} Retrieval successful"; success=true;;
|
"200") echo -e "${OVER} ${TICK} ${str} Retrieval successful"; success=true;;
|
||||||
|
@ -235,16 +242,8 @@ gravity_DownloadBlocklistFromUrl() {
|
||||||
"504") echo -e "${OVER} ${CROSS} ${str} Connection Timed Out (Gateway)";;
|
"504") echo -e "${OVER} ${CROSS} ${str} Connection Timed Out (Gateway)";;
|
||||||
"521") echo -e "${OVER} ${CROSS} ${str} Web Server Is Down (Cloudflare)";;
|
"521") echo -e "${OVER} ${CROSS} ${str} Web Server Is Down (Cloudflare)";;
|
||||||
"522") echo -e "${OVER} ${CROSS} ${str} Connection Timed Out (Cloudflare)";;
|
"522") echo -e "${OVER} ${CROSS} ${str} Connection Timed Out (Cloudflare)";;
|
||||||
* ) echo -e "${OVER} ${CROSS} ${str} ${httpCode}";;
|
* ) echo -e "${OVER} ${CROSS} ${str} ${url} (${httpCode})";;
|
||||||
esac;;
|
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
|
esac
|
||||||
|
|
||||||
# Determine if the blocklist was downloaded and saved correctly
|
# Determine if the blocklist was downloaded and saved correctly
|
||||||
|
@ -279,9 +278,9 @@ gravity_ParseFileIntoDomains() {
|
||||||
# Most of the lists downloaded are already in hosts file format but the spacing/formating is not contigious
|
# 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
|
# 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
|
# 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.
|
# 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
|
# Last awk command takes non-commented lines and if they have 2 fields, take the right field (the domain) and leave
|
||||||
#+ the right (IP address), otherwise grab the single field.
|
# the left (IP address), otherwise grab the single field.
|
||||||
|
|
||||||
< ${source} awk -F '#' '{print $1}' | \
|
< ${source} awk -F '#' '{print $1}' | \
|
||||||
awk -F '/' '{print $1}' | \
|
awk -F '/' '{print $1}' | \
|
||||||
|
@ -345,13 +344,18 @@ gravity_ParseFileIntoDomains() {
|
||||||
# Scanning for "^IPv4$" is too slow with large (1M) lists on low-end hardware
|
# Scanning for "^IPv4$" is too slow with large (1M) lists on low-end hardware
|
||||||
echo -ne " ${INFO} Format: URL"
|
echo -ne " ${INFO} Format: URL"
|
||||||
|
|
||||||
awk '{
|
awk '
|
||||||
# Remove URL protocol, optional "username:password@", and ":?/;"
|
# Remove URL scheme, optional "username:password@", and ":?/;"
|
||||||
if ($0 ~ /[:?\/;]/) { gsub(/(^.*:\/\/(.*:.*@)?|[:?\/;].*)/, "", $0) }
|
# The scheme must be matched carefully to avoid blocking the wrong URL
|
||||||
# Remove lines which are only IPv4 addresses
|
# in cases like:
|
||||||
if ($0 ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) { $0="" }
|
# http://www.evil.com?http://www.good.com
|
||||||
if ($0) { print $0 }
|
# See RFC 3986 section 3.1 for details.
|
||||||
}' "${source}" 2> /dev/null > "${destination}"
|
/[:?\/;]/ { gsub(/(^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/(.*:.*@)?|[:?\/;].*)/, "", $0) }
|
||||||
|
# Skip lines which are only IPv4 addresses
|
||||||
|
/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/ { next }
|
||||||
|
# Print if nonempty
|
||||||
|
length { print }
|
||||||
|
' "${source}" 2> /dev/null > "${destination}"
|
||||||
|
|
||||||
echo -e "${OVER} ${TICK} Format: URL"
|
echo -e "${OVER} ${TICK} Format: URL"
|
||||||
else
|
else
|
||||||
|
@ -371,7 +375,9 @@ gravity_ConsolidateDownloadedBlocklists() {
|
||||||
local str lastLine
|
local str lastLine
|
||||||
|
|
||||||
str="Consolidating blocklists"
|
str="Consolidating blocklists"
|
||||||
echo -ne " ${INFO} ${str}..."
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
|
echo -ne " ${INFO} ${str}..."
|
||||||
|
fi
|
||||||
|
|
||||||
# Empty $matterAndLight if it already exists, otherwise, create it
|
# Empty $matterAndLight if it already exists, otherwise, create it
|
||||||
: > "${piholeDir}/${matterAndLight}"
|
: > "${piholeDir}/${matterAndLight}"
|
||||||
|
@ -390,8 +396,9 @@ gravity_ConsolidateDownloadedBlocklists() {
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
echo -e "${OVER} ${TICK} ${str}"
|
echo -e "${OVER} ${TICK} ${str}"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Parse consolidated list into (filtered, unique) domains-only format
|
# Parse consolidated list into (filtered, unique) domains-only format
|
||||||
|
@ -399,24 +406,33 @@ gravity_SortAndFilterConsolidatedList() {
|
||||||
local str num
|
local str num
|
||||||
|
|
||||||
str="Extracting domains from blocklists"
|
str="Extracting domains from blocklists"
|
||||||
echo -ne " ${INFO} ${str}..."
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
|
echo -ne " ${INFO} ${str}..."
|
||||||
|
fi
|
||||||
|
|
||||||
# Parse into hosts file
|
# Parse into hosts file
|
||||||
gravity_ParseFileIntoDomains "${piholeDir}/${matterAndLight}" "${piholeDir}/${parsedMatter}"
|
gravity_ParseFileIntoDomains "${piholeDir}/${matterAndLight}" "${piholeDir}/${parsedMatter}"
|
||||||
|
|
||||||
# Format $parsedMatter line total as currency
|
# Format $parsedMatter line total as currency
|
||||||
num=$(printf "%'.0f" "$(wc -l < "${piholeDir}/${parsedMatter}")")
|
num=$(printf "%'.0f" "$(wc -l < "${piholeDir}/${parsedMatter}")")
|
||||||
echo -e "${OVER} ${TICK} ${str}
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
${INFO} Number of domains being pulled in by gravity: ${COL_BLUE}${num}${COL_NC}"
|
echo -e "${OVER} ${TICK} ${str}"
|
||||||
|
fi
|
||||||
|
echo -e " ${INFO} Number of domains being pulled in by gravity: ${COL_BLUE}${num}${COL_NC}"
|
||||||
|
|
||||||
str="Removing duplicate domains"
|
str="Removing duplicate domains"
|
||||||
echo -ne " ${INFO} ${str}..."
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
sort -u "${piholeDir}/${parsedMatter}" > "${piholeDir}/${preEventHorizon}"
|
echo -ne " ${INFO} ${str}..."
|
||||||
echo -e "${OVER} ${TICK} ${str}"
|
fi
|
||||||
|
|
||||||
# Format $preEventHorizon line total as currency
|
sort -u "${piholeDir}/${parsedMatter}" > "${piholeDir}/${preEventHorizon}"
|
||||||
num=$(printf "%'.0f" "$(wc -l < "${piholeDir}/${preEventHorizon}")")
|
|
||||||
echo -e " ${INFO} Number of unique domains trapped in the Event Horizon: ${COL_BLUE}${num}${COL_NC}"
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
|
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}"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Whitelist user-defined domains
|
# Whitelist user-defined domains
|
||||||
|
@ -438,7 +454,7 @@ gravity_Whitelist() {
|
||||||
echo -e "${OVER} ${INFO} ${str}"
|
echo -e "${OVER} ${INFO} ${str}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Output count of blacklisted domains and wildcards
|
# Output count of blacklisted domains and regex filters
|
||||||
gravity_ShowBlockCount() {
|
gravity_ShowBlockCount() {
|
||||||
local num
|
local num
|
||||||
|
|
||||||
|
@ -447,13 +463,9 @@ gravity_ShowBlockCount() {
|
||||||
echo -e " ${INFO} Number of blacklisted domains: ${num}"
|
echo -e " ${INFO} Number of blacklisted domains: ${num}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f "${wildcardFile}" ]]; then
|
if [[ -f "${regexFile}" ]]; then
|
||||||
num=$(grep -c "^" "${wildcardFile}")
|
num=$(grep -c "^(?!#)" "${regexFile}")
|
||||||
# If IPv4 and IPv6 is used, divide total wildcard count by 2
|
echo -e " ${INFO} Number of regex filters: ${num}"
|
||||||
if [[ -n "${IPV4_ADDRESS}" ]] && [[ -n "${IPV6_ADDRESS}" ]];then
|
|
||||||
num=$(( num/2 ))
|
|
||||||
fi
|
|
||||||
echo -e " ${INFO} Number of wildcard blocked domains: ${num}"
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,12 +517,12 @@ gravity_ParseBlacklistDomains() {
|
||||||
|
|
||||||
# Empty $accretionDisc if it already exists, otherwise, create it
|
# Empty $accretionDisc if it already exists, otherwise, create it
|
||||||
: > "${piholeDir}/${accretionDisc}"
|
: > "${piholeDir}/${accretionDisc}"
|
||||||
|
|
||||||
if [[ -f "${piholeDir}/${whitelistMatter}" ]]; then
|
if [[ -f "${piholeDir}/${whitelistMatter}" ]]; then
|
||||||
gravity_ParseDomainsIntoHosts "${piholeDir}/${whitelistMatter}" "${piholeDir}/${accretionDisc}"
|
mv "${piholeDir}/${whitelistMatter}" "${piholeDir}/${accretionDisc}"
|
||||||
else
|
else
|
||||||
# There was no whitelist file, so use preEventHorizon instead of whitelistMatter.
|
# There was no whitelist file, so use preEventHorizon instead of whitelistMatter.
|
||||||
gravity_ParseDomainsIntoHosts "${piholeDir}/${preEventHorizon}" "${piholeDir}/${accretionDisc}"
|
mv "${piholeDir}/${preEventHorizon}" "${piholeDir}/${accretionDisc}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Move the file over as /etc/pihole/gravity.list so dnsmasq can use it
|
# Move the file over as /etc/pihole/gravity.list so dnsmasq can use it
|
||||||
|
@ -528,11 +540,9 @@ gravity_ParseUserDomains() {
|
||||||
if [[ ! -f "${blacklistFile}" ]]; then
|
if [[ ! -f "${blacklistFile}" ]]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
gravity_ParseDomainsIntoHosts "${blacklistFile}" "${blackList}.tmp"
|
|
||||||
# Copy the file over as /etc/pihole/black.list so dnsmasq can use it
|
# Copy the file over as /etc/pihole/black.list so dnsmasq can use it
|
||||||
mv "${blackList}.tmp" "${blackList}" 2> /dev/null || \
|
cp "${blacklistFile}" "${blackList}" 2> /dev/null || \
|
||||||
echo -e "\\n ${CROSS} Unable to move ${blackList##*/}.tmp to ${piholeDir}"
|
echo -e "\\n ${CROSS} Unable to move ${blacklistFile##*/} to ${piholeDir}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Trap Ctrl-C
|
# Trap Ctrl-C
|
||||||
|
@ -567,7 +577,7 @@ gravity_Cleanup() {
|
||||||
echo -e "${OVER} ${TICK} ${str}"
|
echo -e "${OVER} ${TICK} ${str}"
|
||||||
|
|
||||||
# Only restart DNS service if offline
|
# Only restart DNS service if offline
|
||||||
if ! pidof dnsmasq &> /dev/null; then
|
if ! pidof ${resolver} &> /dev/null; then
|
||||||
"${PIHOLE_COMMAND}" restartdns
|
"${PIHOLE_COMMAND}" restartdns
|
||||||
dnsWasOffline=true
|
dnsWasOffline=true
|
||||||
fi
|
fi
|
||||||
|
@ -616,7 +626,9 @@ if [[ "${skipDownload}" == false ]]; then
|
||||||
# Gravity needs to download blocklists
|
# Gravity needs to download blocklists
|
||||||
gravity_CheckDNSResolutionAvailable
|
gravity_CheckDNSResolutionAvailable
|
||||||
gravity_GetBlocklistUrls
|
gravity_GetBlocklistUrls
|
||||||
gravity_SetDownloadOptions
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
|
gravity_SetDownloadOptions
|
||||||
|
fi
|
||||||
gravity_ConsolidateDownloadedBlocklists
|
gravity_ConsolidateDownloadedBlocklists
|
||||||
gravity_SortAndFilterConsolidatedList
|
gravity_SortAndFilterConsolidatedList
|
||||||
else
|
else
|
||||||
|
@ -631,6 +643,7 @@ if [[ "${skipDownload}" == false ]] || [[ "${listType}" == "whitelist" ]]; then
|
||||||
gravity_Whitelist
|
gravity_Whitelist
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
convert_wildcard_to_regex
|
||||||
gravity_ShowBlockCount
|
gravity_ShowBlockCount
|
||||||
|
|
||||||
# Perform when downloading blocklists, or modifying the white/blacklist (not wildcards)
|
# Perform when downloading blocklists, or modifying the white/blacklist (not wildcards)
|
||||||
|
|
112
manpages/pihole-FTL.8
Normal file
112
manpages/pihole-FTL.8
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
.TH "Pihole-FTL" "8" "pihole-FTL" "Pi-hole" "June 2018"
|
||||||
|
.SH "NAME"
|
||||||
|
pihole-FTL - Pi-hole : The Faster-Than-Light (FTL) Engine
|
||||||
|
.br
|
||||||
|
.SH "SYNOPSIS"
|
||||||
|
\fBservice pihole-FTL \fR(\fBstart\fR|\fBstop\fR|\fBrestart\fR)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole-FTL debug\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL test\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -v\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -t\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -b\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -f\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -h\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL dnsmasq-test\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL --\fR (\fBoptions\fR)
|
||||||
|
.br
|
||||||
|
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
Pi-hole : The Faster-Than-Light (FTL) Engine is a lightweight, purpose-built daemon used to provide statistics needed for the Pi-hole Web Interface, and its API can be easily integrated into your own projects. Although it is an optional component of the Pi-hole ecosystem, it will be installed by default to provide statistics. As the name implies, FTL does its work \fIvery\fR \fIquickly\fR!
|
||||||
|
.br
|
||||||
|
|
||||||
|
Usage
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBservice pihole-FTL start\fR
|
||||||
|
.br
|
||||||
|
Start the pihole-FTL daemon
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBservice pihole-FTL stop\fR
|
||||||
|
.br
|
||||||
|
Stop the pihole-FTL daemon
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBservice pihole-FTL restart\fR
|
||||||
|
.br
|
||||||
|
If the pihole-FTP daemon is running, stop and then start, otherwise start.
|
||||||
|
.br
|
||||||
|
|
||||||
|
Command line arguments
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBdebug\fR
|
||||||
|
.br
|
||||||
|
Don't go into daemon mode (stay in foreground) + more verbose logging
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBtest\fR
|
||||||
|
.br
|
||||||
|
Start FTL and process everything, but shut down immediately afterwards
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-v, version\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show only version
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-t, tag\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show only git tag
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-b, branch\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show only git branch FTL was compiled from
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-f, no-daemon\fR
|
||||||
|
.br
|
||||||
|
Don't go into background (daemon mode)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-h, help\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show help
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBdnsmasq-test\fR
|
||||||
|
.br
|
||||||
|
Test resolver config file syntax
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB--\fR (options)
|
||||||
|
.br
|
||||||
|
Pass options to internal dnsmasq resolver
|
||||||
|
.br
|
||||||
|
.SH "EXAMPLE"
|
||||||
|
Command line arguments can be arbitrarily combined, e.g:
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole-FTL debug test\fR
|
||||||
|
.br
|
||||||
|
|
||||||
|
Start ftl in foreground with more verbose logging, process everything and shutdown immediately
|
||||||
|
.br
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
\fBpihole\fR(8), \fBpihole-FTL.conf\fR(5)
|
||||||
|
.br
|
||||||
|
.SH "COLOPHON"
|
||||||
|
|
||||||
|
Get sucked into the latest news and community activity by entering Pi-hole's orbit. Information about Pi-hole, and the latest version of the software can be found at https://pi-hole.net
|
||||||
|
.br
|
102
manpages/pihole-FTL.conf.5
Normal file
102
manpages/pihole-FTL.conf.5
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
.TH "pihole-FTL.conf" "5" "pihole-FTL.conf" "pihole-FTL.conf" "June 2018"
|
||||||
|
.SH "NAME"
|
||||||
|
|
||||||
|
pihole-FTL.conf - FTL's config file
|
||||||
|
.br
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
|
||||||
|
/etc/pihole/pihole-FTL.conf will be read by \fBpihole-FTL(8)\fR on startup.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBSOCKET_LISTENING=localonly|all\fR
|
||||||
|
.br
|
||||||
|
Listen only for local socket connections or permit all connections
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBQUERY_DISPLAY=yes|no\fR
|
||||||
|
.br
|
||||||
|
Display all queries? Set to no to hide query display
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBAAAA_QUERY_ANALYSIS=yes|no\fR
|
||||||
|
.br
|
||||||
|
Allow FTL to analyze AAAA queries from pihole.log?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBRESOLVE_IPV6=yes|no\fR
|
||||||
|
.br
|
||||||
|
Should FTL try to resolve IPv6 addresses to host names?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBRESOLVE_IPV4=yes|no\fR
|
||||||
|
.br
|
||||||
|
Should FTL try to resolve IPv4 addresses to host names?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBMAXDBDAYS=365\fR
|
||||||
|
.br
|
||||||
|
How long should queries be stored in the database?
|
||||||
|
.br
|
||||||
|
Setting this to 0 disables the database
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDBINTERVAL=1.0\fR
|
||||||
|
.br
|
||||||
|
How often do we store queries in FTL's database [minutes]?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDBFILE=/etc/pihole/pihole-FTL.db\fR
|
||||||
|
.br
|
||||||
|
Specify path and filename of FTL's SQLite long-term database.
|
||||||
|
.br
|
||||||
|
Setting this to DBFILE= disables the database altogether
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBMAXLOGAGE=24.0\fR
|
||||||
|
.br
|
||||||
|
Up to how many hours of queries should be imported from the database and logs?
|
||||||
|
.br
|
||||||
|
Maximum is 744 (31 days)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBFTLPORT=4711\fR
|
||||||
|
.br
|
||||||
|
On which port should FTL be listening?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBPRIVACYLEVEL=0|1|2|3\fR
|
||||||
|
.br
|
||||||
|
Which privacy level is used?
|
||||||
|
.br
|
||||||
|
0 - show everything
|
||||||
|
.br
|
||||||
|
1 - hide domains
|
||||||
|
.br
|
||||||
|
2 - hide domains and clients
|
||||||
|
.br
|
||||||
|
3 - paranoia mode (hide everything)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBIGNORE_LOCALHOST=no|yes\fR
|
||||||
|
.br
|
||||||
|
Should FTL ignore queries coming from the local machine?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBBLOCKINGMODE=IP|IP-AAAA-NODATA|NXDOMAIN|NULL\fR
|
||||||
|
.br
|
||||||
|
How should FTL reply to blocked queries?
|
||||||
|
.br
|
||||||
|
|
||||||
|
For each setting, the option shown first is the default.
|
||||||
|
.br
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
|
||||||
|
\fBpihole\fR(8), \fBpihole-FTL\fR(8)
|
||||||
|
.br
|
||||||
|
.SH "COLOPHON"
|
||||||
|
|
||||||
|
Pi-hole : The Faster-Than-Light (FTL) Engine is a lightweight, purpose-built daemon used to provide statistics needed for the Pi-hole Web Interface, and its API can be easily integrated into your own projects. Although it is an optional component of the Pi-hole ecosystem, it will be installed by default to provide statistics. As the name implies, FTL does its work \fIvery quickly\fR!
|
||||||
|
.br
|
||||||
|
|
||||||
|
Get sucked into the latest news and community activity by entering Pi-hole's orbit. Information about Pi-hole, and the latest version of the software can be found at https://pi-hole.net
|
||||||
|
.br
|
361
manpages/pihole.8
Normal file
361
manpages/pihole.8
Normal file
|
@ -0,0 +1,361 @@
|
||||||
|
.TH "Pi-hole" "8" "Pi-hole" "Pi-hole" "May 2018"
|
||||||
|
.SH "NAME"
|
||||||
|
|
||||||
|
Pi-hole : A black-hole for internet advertisements
|
||||||
|
.br
|
||||||
|
.SH "SYNOPSIS"
|
||||||
|
|
||||||
|
\fBpihole\fR (\fB-w\fR|\fB-b\fR|\fB--wild\fR|\fB--regex\fR) [options] domain(s)
|
||||||
|
.br
|
||||||
|
\fBpihole -a\fR \fB-p\fR password
|
||||||
|
.br
|
||||||
|
\fBpihole -a\fR (\fB-c|-f|-k\fR)
|
||||||
|
.br
|
||||||
|
\fBpihole -a\fR [\fB-r\fR hostrecord]
|
||||||
|
.br
|
||||||
|
\fBpihole -a -e\fR email
|
||||||
|
.br
|
||||||
|
\fBpihole -a -i\fR interface
|
||||||
|
.br
|
||||||
|
\fBpihole -a -l\fR privacylevel
|
||||||
|
.br
|
||||||
|
\fBpihole -c\fR [-j|-r|-e]
|
||||||
|
.br
|
||||||
|
\fBpihole\fR \fB-d\fR [-a]
|
||||||
|
.br
|
||||||
|
\fBpihole -f
|
||||||
|
.br
|
||||||
|
pihole -r
|
||||||
|
.br
|
||||||
|
pihole -t
|
||||||
|
.br
|
||||||
|
pihole -g\fR
|
||||||
|
.br
|
||||||
|
\fBpihole\fR -\fBq\fR [options]
|
||||||
|
.br
|
||||||
|
\fBpihole\fR \fB-l\fR (\fBon|off|off noflush\fR)
|
||||||
|
.br
|
||||||
|
\fBpihole -up \fR[--checkonly]
|
||||||
|
.br
|
||||||
|
\fBpihole -v\fR [-p|-a|-f] [-c|-l|-hash]
|
||||||
|
.br
|
||||||
|
\fBpihole uninstall
|
||||||
|
.br
|
||||||
|
pihole status
|
||||||
|
.br
|
||||||
|
pihole restartdns\fR
|
||||||
|
.br
|
||||||
|
\fBpihole\fR (\fBenable\fR|\fBdisable\fR [time])
|
||||||
|
.br
|
||||||
|
\fBpihole\fR \fBcheckout\fR repo [branch]
|
||||||
|
.br
|
||||||
|
\fBpihole\fR \fBhelp\fR
|
||||||
|
.br
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
|
||||||
|
Available commands and options:
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-w, whitelist\fR [options] [<domain1> <domain2 ...>]
|
||||||
|
.br
|
||||||
|
Adds or removes specified domain or domains tho the Whitelist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-b, blacklist\fR [options] [<domain1> <domain2 ...>]
|
||||||
|
.br
|
||||||
|
Adds or removes specified domain or domains to the blacklist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB--wild, wildcard\fR [options] [<domain1> <domain2 ...>]
|
||||||
|
.br
|
||||||
|
Add or removes specified domain to the wildcard blacklist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB--regex, regex\fR [options] [<regex1> <regex2 ...>]
|
||||||
|
.br
|
||||||
|
Add or removes specified regex filter to the regex blacklist
|
||||||
|
.br
|
||||||
|
|
||||||
|
(Whitelist/Blacklist manipulation options):
|
||||||
|
.br
|
||||||
|
-d, --delmode Remove domain(s) from the list
|
||||||
|
.br
|
||||||
|
-nr, --noreload Update list without refreshing dnsmasq
|
||||||
|
.br
|
||||||
|
-q, --quiet Make output less verbose
|
||||||
|
.br
|
||||||
|
-l, --list Display all your listed domains
|
||||||
|
.br
|
||||||
|
--nuke Removes all entries in a list
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-d, debug\fR [-a]
|
||||||
|
.br
|
||||||
|
Start a debugging session
|
||||||
|
.br
|
||||||
|
|
||||||
|
-a Enable automated debugging
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-f, flush\fR
|
||||||
|
.br
|
||||||
|
Flush the Pi-hole log
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-r, reconfigure\fR
|
||||||
|
.br
|
||||||
|
Reconfigure or Repair Pi-hole subsystems
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-t, tail\fR
|
||||||
|
.br
|
||||||
|
View the live output of the Pi-hole log
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-a, admin\fR [options]
|
||||||
|
.br
|
||||||
|
|
||||||
|
(Admin options):
|
||||||
|
.br
|
||||||
|
-p, password Set Web Interface password
|
||||||
|
.br
|
||||||
|
-c, celsius Set Celsius as preferred temperature unit
|
||||||
|
.br
|
||||||
|
-f, fahrenheit Set Fahrenheit as preferred temperature unit
|
||||||
|
.br
|
||||||
|
-k, kelvin Set Kelvin as preferred temperature unit
|
||||||
|
.br
|
||||||
|
-r, hostrecord Add a name to the DNS associated to an
|
||||||
|
IPv4/IPv6 address
|
||||||
|
.br
|
||||||
|
-e, email Set an administrative contact address for the
|
||||||
|
Block Page
|
||||||
|
.br
|
||||||
|
-i, interface Specify dnsmasq's interface listening behavior
|
||||||
|
.br
|
||||||
|
-l, privacylevel <level> Set privacy level
|
||||||
|
(0 = lowest, 3 = highest)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-c, chronometer\fR [options]
|
||||||
|
.br
|
||||||
|
Calculates stats and displays to an LCD
|
||||||
|
.br
|
||||||
|
|
||||||
|
(Chronometer Options):
|
||||||
|
.br
|
||||||
|
-j, --json Output stats as JSON formatted string
|
||||||
|
.br
|
||||||
|
-r, --refresh Set update frequency (in seconds)
|
||||||
|
.br
|
||||||
|
-e, --exit Output stats and exit witout refreshing
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-g, updateGravity\fR
|
||||||
|
.br
|
||||||
|
Update the list of ad-serving domains
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-q, query\fR [option]
|
||||||
|
.br
|
||||||
|
Query the adlists for a specified domain
|
||||||
|
.br
|
||||||
|
|
||||||
|
(Query options):
|
||||||
|
.br
|
||||||
|
-adlist Print the name of the block list URL
|
||||||
|
.br
|
||||||
|
-exact Search the block lists for exact domain matches
|
||||||
|
.br
|
||||||
|
-all Return all query matches within a block list
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-h, --help, help\fR
|
||||||
|
.br
|
||||||
|
Show a help dialog
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-l, logging\fR [on|off|off noflush]
|
||||||
|
.br
|
||||||
|
Specify whether the Pi-hole log should be used
|
||||||
|
.br
|
||||||
|
|
||||||
|
(Logging options):
|
||||||
|
.br
|
||||||
|
on Enable the Pi-hole log at /var/log/pihole.log
|
||||||
|
.br
|
||||||
|
off Disable and flush the Pi-hole log at
|
||||||
|
/var/log/pihole.log
|
||||||
|
.br
|
||||||
|
off noflush Disable the Pi-hole log at /var/log/pihole.log
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-up, updatePihole\fR [--check-only]
|
||||||
|
.br
|
||||||
|
Update Pi-hole subsystems
|
||||||
|
.br
|
||||||
|
|
||||||
|
--check-only Exit script before update is performed.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-v, version\fR [repo] [options]
|
||||||
|
.br
|
||||||
|
Show installed versions of Pi-hole, Web Interface & FTL
|
||||||
|
.br
|
||||||
|
|
||||||
|
.br
|
||||||
|
(repo options):
|
||||||
|
.br
|
||||||
|
-p, --pihole Only retrieve info regarding Pi-hole repository
|
||||||
|
.br
|
||||||
|
-a, --admin Only retrieve info regarding AdminLTE
|
||||||
|
repository
|
||||||
|
.br
|
||||||
|
-f, --ftl Only retrieve info regarding FTL repository
|
||||||
|
.br
|
||||||
|
(version options):
|
||||||
|
.br
|
||||||
|
-c, --current Return the current version
|
||||||
|
.br
|
||||||
|
-l, --latest Return the latest version
|
||||||
|
.br
|
||||||
|
--hash Return the Github hash from your local
|
||||||
|
repositories
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBuninstall\fR
|
||||||
|
.br
|
||||||
|
Uninstall Pi-hole from your system
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBstatus\fR
|
||||||
|
.br
|
||||||
|
Display the running status of Pi-hole subsystems
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBenable\fR
|
||||||
|
.br
|
||||||
|
Enable Pi-hole subsystems
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBdisable\fR [time]
|
||||||
|
.br
|
||||||
|
Disable Pi-hole subsystems, optionally for a set duration
|
||||||
|
.br
|
||||||
|
|
||||||
|
(time options):
|
||||||
|
.br
|
||||||
|
#s Disable Pi-hole functionality for # second(s)
|
||||||
|
.br
|
||||||
|
#m Disable Pi-hole functionality for # minute(s)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBrestartdns\fR
|
||||||
|
.br
|
||||||
|
Restart Pi-hole subsystems
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBcheckout\fR [repo] [branch]
|
||||||
|
.br
|
||||||
|
Switch Pi-hole subsystems to a different Github branch
|
||||||
|
.br
|
||||||
|
|
||||||
|
(repo options):
|
||||||
|
.br
|
||||||
|
core Change the branch of Pi-hole's core subsystem
|
||||||
|
.br
|
||||||
|
web Change the branch of Admin Console subsystem
|
||||||
|
.br
|
||||||
|
ftl Change the branch of Pi-hole's FTL subsystem
|
||||||
|
.br
|
||||||
|
(branch options):
|
||||||
|
.br
|
||||||
|
master Update subsystems to the latest stable release
|
||||||
|
.br
|
||||||
|
dev Update subsystems to the latest development
|
||||||
|
release
|
||||||
|
.br
|
||||||
|
branchname Update subsystems to the specified branchname
|
||||||
|
.br
|
||||||
|
.SH "EXAMPLE"
|
||||||
|
|
||||||
|
Some usage examples
|
||||||
|
.br
|
||||||
|
|
||||||
|
Whitelist/blacklist manipulation
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole -w iloveads.example.com\fR
|
||||||
|
.br
|
||||||
|
Adds "iloveads.example.com" to whitelist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole -b -d noads.example.com\fR
|
||||||
|
.br
|
||||||
|
Removes "noads.example.com" from blacklist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole --wild example.com\fR
|
||||||
|
.br
|
||||||
|
Adds example.com as a wildcard - would block all subdomains of
|
||||||
|
example.com, including example.com itself.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole --regex "ad.*\\.example\\.com$"\fR
|
||||||
|
.br
|
||||||
|
Adds "ad.*\\.example\\.com$" to the regex blacklist.
|
||||||
|
Would block all subdomains of example.com which start with "ad"
|
||||||
|
.br
|
||||||
|
|
||||||
|
Changing the Web Interface password
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole -a -p ExamplePassword\fR
|
||||||
|
.br
|
||||||
|
Change the password to "ExamplePassword"
|
||||||
|
.br
|
||||||
|
|
||||||
|
Updating lists from internet sources
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole -g\fR
|
||||||
|
.br
|
||||||
|
Update the list of ad-serving domains
|
||||||
|
.br
|
||||||
|
|
||||||
|
Displaying version information
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole -v -a -c\fR
|
||||||
|
.br
|
||||||
|
Display the current version of AdminLTE
|
||||||
|
.br
|
||||||
|
|
||||||
|
Temporarily disabling Pi-hole
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole disable 5m\fR
|
||||||
|
.br
|
||||||
|
Disable Pi-hole functionality for five minutes
|
||||||
|
.br
|
||||||
|
|
||||||
|
Switching Pi-hole subsystem branches
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole checkout master\fR
|
||||||
|
.br
|
||||||
|
Switch to master branch
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole checkout core dev\fR
|
||||||
|
.br
|
||||||
|
Switch to core development branch
|
||||||
|
.br
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
|
||||||
|
\fBlighttpd\fR(8), \fBpihole-FTL\fR(8)
|
||||||
|
.br
|
||||||
|
.SH "COLOPHON"
|
||||||
|
|
||||||
|
Get sucked into the latest news and community activity by entering Pi-hole's orbit. Information about Pi-hole, and the latest version of the software can be found at https://pi-hole.net.
|
||||||
|
.br
|
286
pihole
286
pihole
|
@ -14,6 +14,8 @@ readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
|
||||||
readonly colfile="${PI_HOLE_SCRIPT_DIR}/COL_TABLE"
|
readonly colfile="${PI_HOLE_SCRIPT_DIR}/COL_TABLE"
|
||||||
source "${colfile}"
|
source "${colfile}"
|
||||||
|
|
||||||
|
resolver="pihole-FTL"
|
||||||
|
|
||||||
# Must be root to use this tool
|
# Must be root to use this tool
|
||||||
if [[ ! $EUID -eq 0 ]];then
|
if [[ ! $EUID -eq 0 ]];then
|
||||||
if [[ -x "$(command -v sudo)" ]]; then
|
if [[ -x "$(command -v sudo)" ]]; then
|
||||||
|
@ -31,17 +33,7 @@ webpageFunc() {
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
whitelistFunc() {
|
listFunc() {
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
blacklistFunc() {
|
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
wildcardFunc() {
|
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
|
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
@ -69,7 +61,8 @@ flushFunc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePiholeFunc() {
|
updatePiholeFunc() {
|
||||||
"${PI_HOLE_SCRIPT_DIR}"/update.sh
|
shift
|
||||||
|
"${PI_HOLE_SCRIPT_DIR}"/update.sh "$@"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,230 +76,9 @@ updateGravityFunc() {
|
||||||
exit 0
|
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() {
|
queryFunc() {
|
||||||
shift
|
shift
|
||||||
local options="$*" adlist="" all="" exact="" blockpage="" matchType="match"
|
"${PI_HOLE_SCRIPT_DIR}"/query.sh "$@"
|
||||||
|
|
||||||
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
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,18 +104,18 @@ restartDNS() {
|
||||||
local svcOption svc str output status
|
local svcOption svc str output status
|
||||||
svcOption="${1:-}"
|
svcOption="${1:-}"
|
||||||
|
|
||||||
# Determine if we should reload or restart dnsmasq
|
# Determine if we should reload or restart restart
|
||||||
if [[ "${svcOption}" =~ "reload" ]]; then
|
if [[ "${svcOption}" =~ "reload" ]]; then
|
||||||
# Using SIGHUP will NOT re-read any *.conf files
|
# Using SIGHUP will NOT re-read any *.conf files
|
||||||
svc="killall -s SIGHUP dnsmasq"
|
svc="killall -s SIGHUP ${resolver}"
|
||||||
else
|
else
|
||||||
# Get PID of dnsmasq to determine if it needs to start or restart
|
# Get PID of resolver to determine if it needs to start or restart
|
||||||
if pidof dnsmasq &> /dev/null; then
|
if pidof pihole-FTL &> /dev/null; then
|
||||||
svcOption="restart"
|
svcOption="restart"
|
||||||
else
|
else
|
||||||
svcOption="start"
|
svcOption="start"
|
||||||
fi
|
fi
|
||||||
svc="service dnsmasq ${svcOption}"
|
svc="service ${resolver} ${svcOption}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Print output to Terminal, but not to Web Admin
|
# Print output to Terminal, but not to Web Admin
|
||||||
|
@ -359,9 +131,6 @@ restartDNS() {
|
||||||
[[ ! -t 1 ]] && local OVER=""
|
[[ ! -t 1 ]] && local OVER=""
|
||||||
echo -e "${OVER} ${CROSS} ${output}"
|
echo -e "${OVER} ${CROSS} ${output}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Send signal to FTL to have it re-parse the gravity files
|
|
||||||
killall -s SIGHUP pihole-FTL
|
|
||||||
}
|
}
|
||||||
|
|
||||||
piholeEnable() {
|
piholeEnable() {
|
||||||
|
@ -476,7 +245,7 @@ statusFunc() {
|
||||||
local addnConfigs
|
local addnConfigs
|
||||||
|
|
||||||
# Determine if service is running on port 53 (Cr: https://superuser.com/a/806331)
|
# 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 (echo > /dev/tcp/127.0.0.1/53) >/dev/null 2>&1; then
|
||||||
if [[ "${1}" != "web" ]]; then
|
if [[ "${1}" != "web" ]]; then
|
||||||
echo -e " ${TICK} DNS service is running"
|
echo -e " ${TICK} DNS service is running"
|
||||||
fi
|
fi
|
||||||
|
@ -516,6 +285,13 @@ statusFunc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
tailFunc() {
|
tailFunc() {
|
||||||
|
# Warn user if Pi-hole's logging is disabled
|
||||||
|
local logging_enabled=$(grep -c "^log-queries" /etc/dnsmasq.d/01-pihole.conf)
|
||||||
|
if [[ "${logging_enabled}" == "0" ]]; then
|
||||||
|
# No "log-queries" lines are found.
|
||||||
|
# Commented out lines (such as "#log-queries") are ignored
|
||||||
|
echo " ${CROSS} Warning: Query logging is disabled"
|
||||||
|
fi
|
||||||
echo -e " ${INFO} Press Ctrl-C to exit"
|
echo -e " ${INFO} Press Ctrl-C to exit"
|
||||||
|
|
||||||
# Retrieve IPv4/6 addresses
|
# Retrieve IPv4/6 addresses
|
||||||
|
@ -541,12 +317,13 @@ Switch Pi-hole subsystems to a different Github branch
|
||||||
|
|
||||||
Repositories:
|
Repositories:
|
||||||
core [branch] Change the branch of Pi-hole's core subsystem
|
core [branch] Change the branch of Pi-hole's core subsystem
|
||||||
web [branch] Change the branch of Admin Console subsystem
|
web [branch] Change the branch of Web Interface subsystem
|
||||||
ftl [branch] Change the branch of Pi-hole's FTL subsystem
|
ftl [branch] Change the branch of Pi-hole's FTL subsystem
|
||||||
|
|
||||||
Branches:
|
Branches:
|
||||||
master Update subsystems to the latest stable release
|
master Update subsystems to the latest stable release
|
||||||
dev Update subsystems to the latest development release"
|
dev Update subsystems to the latest development release
|
||||||
|
branchname Update subsystems to the specified branchname"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -599,7 +376,8 @@ Add '-h' after specific commands for more information on usage
|
||||||
Whitelist/Blacklist Options:
|
Whitelist/Blacklist Options:
|
||||||
-w, whitelist Whitelist domain(s)
|
-w, whitelist Whitelist domain(s)
|
||||||
-b, blacklist Blacklist domain(s)
|
-b, blacklist Blacklist domain(s)
|
||||||
-wild, wildcard Blacklist domain(s), and all its subdomains
|
--wild, wildcard Wildcard blacklist domain(s)
|
||||||
|
--regex, regex Regex blacklist domains(s)
|
||||||
Add '-h' for more info on whitelist/blacklist usage
|
Add '-h' for more info on whitelist/blacklist usage
|
||||||
|
|
||||||
Debugging Options:
|
Debugging Options:
|
||||||
|
@ -610,8 +388,8 @@ Debugging Options:
|
||||||
-t, tail View the live output of the Pi-hole log
|
-t, tail View the live output of the Pi-hole log
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-a, admin Admin Console options
|
-a, admin Web interface options
|
||||||
Add '-h' for more info on admin console usage
|
Add '-h' for more info on Web Interface usage
|
||||||
-c, chronometer Calculates stats and displays to an LCD
|
-c, chronometer Calculates stats and displays to an LCD
|
||||||
Add '-h' for more info on chronometer usage
|
Add '-h' for more info on chronometer usage
|
||||||
-g, updateGravity Update the list of ad-serving domains
|
-g, updateGravity Update the list of ad-serving domains
|
||||||
|
@ -621,7 +399,8 @@ Options:
|
||||||
-q, query Query the adlists for a specified domain
|
-q, query Query the adlists for a specified domain
|
||||||
Add '-h' for more info on query usage
|
Add '-h' for more info on query usage
|
||||||
-up, updatePihole Update Pi-hole subsystems
|
-up, updatePihole Update Pi-hole subsystems
|
||||||
-v, version Show installed versions of Pi-hole, Admin Console & FTL
|
Add '--check-only' to exit script before update is performed.
|
||||||
|
-v, version Show installed versions of Pi-hole, Web Interface & FTL
|
||||||
Add '-h' for more info on version usage
|
Add '-h' for more info on version usage
|
||||||
uninstall Uninstall Pi-hole from your system
|
uninstall Uninstall Pi-hole from your system
|
||||||
status Display the running status of Pi-hole subsystems
|
status Display the running status of Pi-hole subsystems
|
||||||
|
@ -640,12 +419,13 @@ fi
|
||||||
|
|
||||||
# Handle redirecting to specific functions based on arguments
|
# Handle redirecting to specific functions based on arguments
|
||||||
case "${1}" in
|
case "${1}" in
|
||||||
"-w" | "whitelist" ) whitelistFunc "$@";;
|
"-w" | "whitelist" ) listFunc "$@";;
|
||||||
"-b" | "blacklist" ) blacklistFunc "$@";;
|
"-b" | "blacklist" ) listFunc "$@";;
|
||||||
"-wild" | "wildcard" ) wildcardFunc "$@";;
|
"--wild" | "wildcard" ) listFunc "$@";;
|
||||||
|
"--regex" | "regex" ) listFunc "$@";;
|
||||||
"-d" | "debug" ) debugFunc "$@";;
|
"-d" | "debug" ) debugFunc "$@";;
|
||||||
"-f" | "flush" ) flushFunc "$@";;
|
"-f" | "flush" ) flushFunc "$@";;
|
||||||
"-up" | "updatePihole" ) updatePiholeFunc;;
|
"-up" | "updatePihole" ) updatePiholeFunc "$@";;
|
||||||
"-r" | "reconfigure" ) reconfigurePiholeFunc;;
|
"-r" | "reconfigure" ) reconfigurePiholeFunc;;
|
||||||
"-g" | "updateGravity" ) updateGravityFunc "$@";;
|
"-g" | "updateGravity" ) updateGravityFunc "$@";;
|
||||||
"-c" | "chronometer" ) chronometerFunc "$@";;
|
"-c" | "chronometer" ) chronometerFunc "$@";;
|
||||||
|
|
|
@ -3,3 +3,4 @@ pytest
|
||||||
pytest-xdist
|
pytest-xdist
|
||||||
pytest-cov
|
pytest-cov
|
||||||
testinfra
|
testinfra
|
||||||
|
tox
|
||||||
|
|
6
setup.py
Normal file
6
setup.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
setup_requires=['pytest-runner'],
|
||||||
|
tests_require=['pytest'],
|
||||||
|
)
|
25
test/README.md
Normal file
25
test/README.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Recommended way to run tests
|
||||||
|
|
||||||
|
Make sure you have Docker and Python w/pip package manager.
|
||||||
|
|
||||||
|
From command line all you need to do is:
|
||||||
|
|
||||||
|
- `pip install tox`
|
||||||
|
- `tox`
|
||||||
|
|
||||||
|
Tox handles setting up a virtual environment for python dependancies, installing dependancies, building the docker images used by tests, and finally running tests. It's an easy way to have travis-ci like build behavior locally.
|
||||||
|
|
||||||
|
## Alternative py.test method of running tests
|
||||||
|
|
||||||
|
You're responsible for setting up your virtual env and dependancies in this situation.
|
||||||
|
|
||||||
|
```
|
||||||
|
py.test -vv -n auto -m "build_stage"
|
||||||
|
py.test -vv -n auto -m "not build_stage"
|
||||||
|
```
|
||||||
|
|
||||||
|
The build_stage tests have to run first to create the docker images, followed by the actual tests which utilize said images. Unless you're changing your dockerfiles you shouldn't have to run the build_stage every time - but it's a good idea to rebuild at least once a day in case the base Docker images or packages change.
|
||||||
|
|
||||||
|
# How do I debug python?
|
||||||
|
|
||||||
|
Highly recommended: Setup PyCharm on a **Docker enabled** machine. Having a python debugger like PyCharm changes your life if you've never used it :)
|
113
test/conftest.py
113
test/conftest.py
|
@ -1,14 +1,30 @@
|
||||||
import pytest
|
import pytest
|
||||||
import testinfra
|
import testinfra
|
||||||
|
from textwrap import dedent
|
||||||
|
|
||||||
check_output = testinfra.get_backend(
|
check_output = testinfra.get_backend(
|
||||||
"local://"
|
"local://"
|
||||||
).get_module("Command").check_output
|
).get_module("Command").check_output
|
||||||
|
|
||||||
|
SETUPVARS = {
|
||||||
|
'PIHOLE_INTERFACE': 'eth99',
|
||||||
|
'IPV4_ADDRESS': '1.1.1.1',
|
||||||
|
'IPV6_ADDRESS': 'FE80::240:D0FF:FE48:4672',
|
||||||
|
'PIHOLE_DNS_1': '4.2.2.1',
|
||||||
|
'PIHOLE_DNS_2': '4.2.2.2'
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def Pihole(Docker):
|
def Pihole(Docker):
|
||||||
''' used to contain some script stubbing, now pretty much an alias.
|
'''
|
||||||
Also provides bash as the default run function shell '''
|
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):
|
def run_bash(self, command, *args, **kwargs):
|
||||||
cmd = self.get_command(command, *args)
|
cmd = self.get_command(command, *args)
|
||||||
if self.user is not None:
|
if self.user is not None:
|
||||||
|
@ -22,12 +38,18 @@ def Pihole(Docker):
|
||||||
return out
|
return out
|
||||||
|
|
||||||
funcType = type(Docker.run)
|
funcType = type(Docker.run)
|
||||||
Docker.run = funcType(run_bash, Docker, testinfra.backend.docker.DockerBackend)
|
Docker.run = funcType(run_bash,
|
||||||
|
Docker,
|
||||||
|
testinfra.backend.docker.DockerBackend)
|
||||||
return Docker
|
return Docker
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def Docker(request, args, image, cmd):
|
def Docker(request, args, image, cmd):
|
||||||
''' combine our fixtures into a docker run command and setup finalizer to cleanup '''
|
'''
|
||||||
|
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?"
|
assert 'docker' in check_output('id'), "Are you in the docker group?"
|
||||||
docker_run = "docker run {} {} {}".format(args, image, cmd)
|
docker_run = "docker run {} {} {}".format(args, image, cmd)
|
||||||
docker_id = check_output(docker_run)
|
docker_id = check_output(docker_run)
|
||||||
|
@ -40,22 +62,95 @@ def Docker(request, args, image, cmd):
|
||||||
docker_container.id = docker_id
|
docker_container.id = docker_id
|
||||||
return docker_container
|
return docker_container
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def args(request):
|
def args(request):
|
||||||
''' -t became required when tput began being used '''
|
'''
|
||||||
|
-t became required when tput began being used
|
||||||
|
'''
|
||||||
return '-t -d'
|
return '-t -d'
|
||||||
|
|
||||||
@pytest.fixture(params=['debian', 'centos'])
|
|
||||||
|
@pytest.fixture(params=['debian', 'centos', 'fedora'])
|
||||||
def tag(request):
|
def tag(request):
|
||||||
''' consumed by image to make the test matrix '''
|
'''
|
||||||
|
consumed by image to make the test matrix
|
||||||
|
'''
|
||||||
return request.param
|
return request.param
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def image(request, tag):
|
def image(request, tag):
|
||||||
''' built by test_000_build_containers.py '''
|
'''
|
||||||
|
built by test_000_build_containers.py
|
||||||
|
'''
|
||||||
return 'pytest_pihole:{}'.format(tag)
|
return 'pytest_pihole:{}'.format(tag)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def cmd(request):
|
def cmd(request):
|
||||||
''' default to doing nothing by tailing null, but don't exit '''
|
'''
|
||||||
|
default to doing nothing by tailing null, but don't exit
|
||||||
|
'''
|
||||||
return 'tail -f /dev/null'
|
return 'tail -f /dev/null'
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
16
test/fedora.Dockerfile
Normal file
16
test/fedora.Dockerfile
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
FROM fedora:latest
|
||||||
|
|
||||||
|
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 && \
|
|
@ -6,10 +6,15 @@ run_local = testinfra.get_backend(
|
||||||
"local://"
|
"local://"
|
||||||
).get_module("Command").run
|
).get_module("Command").run
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("image,tag", [
|
@pytest.mark.parametrize("image,tag", [
|
||||||
( 'test/debian.Dockerfile', 'pytest_pihole:debian' ),
|
('test/debian.Dockerfile', 'pytest_pihole:debian'),
|
||||||
( 'test/centos.Dockerfile', 'pytest_pihole:centos' ),
|
('test/centos.Dockerfile', 'pytest_pihole:centos'),
|
||||||
|
('test/fedora.Dockerfile', 'pytest_pihole:fedora'),
|
||||||
])
|
])
|
||||||
|
# mark as 'build_stage' so we can ensure images are build first when tests
|
||||||
|
# are executed in parallel. (not required when tests are executed serially)
|
||||||
|
@pytest.mark.build_stage
|
||||||
def test_build_pihole_image(image, tag):
|
def test_build_pihole_image(image, tag):
|
||||||
build_cmd = run_local('docker build -f {} -t {} .'.format(image, tag))
|
build_cmd = run_local('docker build -f {} -t {} .'.format(image, tag))
|
||||||
if build_cmd.rc != 0:
|
if build_cmd.rc != 0:
|
||||||
|
|
|
@ -1,24 +1,40 @@
|
||||||
import pytest
|
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
import re
|
||||||
|
from conftest import (
|
||||||
|
SETUPVARS,
|
||||||
|
tick_box,
|
||||||
|
info_box,
|
||||||
|
cross_box,
|
||||||
|
mock_command,
|
||||||
|
mock_command_2,
|
||||||
|
run_script
|
||||||
|
)
|
||||||
|
|
||||||
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")
|
def test_supported_operating_system(Pihole):
|
||||||
cross_box="[\x1b[1;31m\xe2\x9c\x97\x1b[0m]".decode("utf-8")
|
'''
|
||||||
info_box="[i]".decode("utf-8")
|
confirm installer exists on unsupported distribution
|
||||||
|
'''
|
||||||
|
# break supported package managers to emulate an unsupported distribution
|
||||||
|
Pihole.run('rm -rf /usr/bin/apt-get')
|
||||||
|
Pihole.run('rm -rf /usr/bin/rpm')
|
||||||
|
distro_check = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
distro_check
|
||||||
|
''')
|
||||||
|
expected_stdout = cross_box + ' OS distribution not supported'
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
# assert distro_check.rc == 1
|
||||||
|
|
||||||
|
|
||||||
def test_setupVars_are_sourced_to_global_scope(Pihole):
|
def test_setupVars_are_sourced_to_global_scope(Pihole):
|
||||||
''' currently update_dialogs sources setupVars with a dot,
|
'''
|
||||||
|
currently update_dialogs sources setupVars with a dot,
|
||||||
then various other functions use the variables.
|
then various other functions use the variables.
|
||||||
This confirms the sourced variables are in scope between functions '''
|
This confirms the sourced variables are in scope between functions
|
||||||
|
'''
|
||||||
setup_var_file = 'cat <<EOF> /etc/pihole/setupVars.conf\n'
|
setup_var_file = 'cat <<EOF> /etc/pihole/setupVars.conf\n'
|
||||||
for k,v in SETUPVARS.iteritems():
|
for k, v in SETUPVARS.iteritems():
|
||||||
setup_var_file += "{}={}\n".format(k, v)
|
setup_var_file += "{}={}\n".format(k, v)
|
||||||
setup_var_file += "EOF\n"
|
setup_var_file += "EOF\n"
|
||||||
Pihole.run(setup_var_file)
|
Pihole.run(setup_var_file)
|
||||||
|
@ -43,13 +59,17 @@ def test_setupVars_are_sourced_to_global_scope(Pihole):
|
||||||
|
|
||||||
output = run_script(Pihole, script).stdout
|
output = run_script(Pihole, script).stdout
|
||||||
|
|
||||||
for k,v in SETUPVARS.iteritems():
|
for k, v in SETUPVARS.iteritems():
|
||||||
assert "{}={}".format(k, v) in output
|
assert "{}={}".format(k, v) in output
|
||||||
|
|
||||||
|
|
||||||
def test_setupVars_saved_to_file(Pihole):
|
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
|
confirm saved settings are written to a file for future updates to re-use
|
||||||
for k,v in SETUPVARS.iteritems():
|
'''
|
||||||
|
# dedent works better with this and padding matching script below
|
||||||
|
set_setup_vars = '\n'
|
||||||
|
for k, v in SETUPVARS.iteritems():
|
||||||
set_setup_vars += " {}={}\n".format(k, v)
|
set_setup_vars += " {}={}\n".format(k, v)
|
||||||
Pihole.run(set_setup_vars).stdout
|
Pihole.run(set_setup_vars).stdout
|
||||||
|
|
||||||
|
@ -67,43 +87,57 @@ def test_setupVars_saved_to_file(Pihole):
|
||||||
|
|
||||||
output = run_script(Pihole, script).stdout
|
output = run_script(Pihole, script).stdout
|
||||||
|
|
||||||
for k,v in SETUPVARS.iteritems():
|
for k, v in SETUPVARS.iteritems():
|
||||||
assert "{}={}".format(k, v) in output
|
assert "{}={}".format(k, v) in output
|
||||||
|
|
||||||
|
|
||||||
def test_configureFirewall_firewalld_running_no_errors(Pihole):
|
def test_configureFirewall_firewalld_running_no_errors(Pihole):
|
||||||
''' confirms firewalld rules are applied when firewallD is running '''
|
'''
|
||||||
|
confirms firewalld rules are applied when firewallD is running
|
||||||
|
'''
|
||||||
# firewallD returns 'running' as status
|
# firewallD returns 'running' as status
|
||||||
mock_command('firewall-cmd', {'*':('running', 0)}, Pihole)
|
mock_command('firewall-cmd', {'*': ('running', 0)}, Pihole)
|
||||||
# Whiptail dialog returns Ok for user prompt
|
# Whiptail dialog returns Ok for user prompt
|
||||||
mock_command('whiptail', {'*':('', 0)}, Pihole)
|
mock_command('whiptail', {'*': ('', 0)}, Pihole)
|
||||||
configureFirewall = Pihole.run('''
|
configureFirewall = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
configureFirewall
|
configureFirewall
|
||||||
''')
|
''')
|
||||||
expected_stdout = 'Configuring FirewallD for httpd and dnsmasq'
|
expected_stdout = 'Configuring FirewallD for httpd and pihole-FTL'
|
||||||
assert expected_stdout in configureFirewall.stdout
|
assert expected_stdout in configureFirewall.stdout
|
||||||
firewall_calls = Pihole.run('cat /var/log/firewall-cmd').stdout
|
firewall_calls = Pihole.run('cat /var/log/firewall-cmd').stdout
|
||||||
assert 'firewall-cmd --state' in firewall_calls
|
assert 'firewall-cmd --state' in firewall_calls
|
||||||
assert 'firewall-cmd --permanent --add-service=http --add-service=dns' in firewall_calls
|
assert ('firewall-cmd '
|
||||||
|
'--permanent '
|
||||||
|
'--add-service=http '
|
||||||
|
'--add-service=dns') in firewall_calls
|
||||||
assert 'firewall-cmd --reload' in firewall_calls
|
assert 'firewall-cmd --reload' in firewall_calls
|
||||||
|
|
||||||
|
|
||||||
def test_configureFirewall_firewalld_disabled_no_errors(Pihole):
|
def test_configureFirewall_firewalld_disabled_no_errors(Pihole):
|
||||||
''' confirms firewalld rules are not applied when firewallD is not running '''
|
'''
|
||||||
|
confirms firewalld rules are not applied when firewallD is not running
|
||||||
|
'''
|
||||||
# firewallD returns non-running status
|
# firewallD returns non-running status
|
||||||
mock_command('firewall-cmd', {'*':('not running', '1')}, Pihole)
|
mock_command('firewall-cmd', {'*': ('not running', '1')}, Pihole)
|
||||||
configureFirewall = Pihole.run('''
|
configureFirewall = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
configureFirewall
|
configureFirewall
|
||||||
''')
|
''')
|
||||||
expected_stdout = 'No active firewall detected.. skipping firewall configuration'
|
expected_stdout = ('No active firewall detected.. '
|
||||||
|
'skipping firewall configuration')
|
||||||
assert expected_stdout in configureFirewall.stdout
|
assert expected_stdout in configureFirewall.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_configureFirewall_firewalld_enabled_declined_no_errors(Pihole):
|
def test_configureFirewall_firewalld_enabled_declined_no_errors(Pihole):
|
||||||
''' confirms firewalld rules are not applied when firewallD is running, user declines ruleset '''
|
'''
|
||||||
|
confirms firewalld rules are not applied when firewallD is running, user
|
||||||
|
declines ruleset
|
||||||
|
'''
|
||||||
# firewallD returns running status
|
# firewallD returns running status
|
||||||
mock_command('firewall-cmd', {'*':('running', 0)}, Pihole)
|
mock_command('firewall-cmd', {'*': ('running', 0)}, Pihole)
|
||||||
# Whiptail dialog returns Cancel for user prompt
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
mock_command('whiptail', {'*':('', 1)}, Pihole)
|
mock_command('whiptail', {'*': ('', 1)}, Pihole)
|
||||||
configureFirewall = Pihole.run('''
|
configureFirewall = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
configureFirewall
|
configureFirewall
|
||||||
|
@ -111,6 +145,7 @@ def test_configureFirewall_firewalld_enabled_declined_no_errors(Pihole):
|
||||||
expected_stdout = 'Not installing firewall rulesets.'
|
expected_stdout = 'Not installing firewall rulesets.'
|
||||||
assert expected_stdout in configureFirewall.stdout
|
assert expected_stdout in configureFirewall.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_configureFirewall_no_firewall(Pihole):
|
def test_configureFirewall_no_firewall(Pihole):
|
||||||
''' confirms firewall skipped no daemon is running '''
|
''' confirms firewall skipped no daemon is running '''
|
||||||
configureFirewall = Pihole.run('''
|
configureFirewall = Pihole.run('''
|
||||||
|
@ -120,14 +155,18 @@ def test_configureFirewall_no_firewall(Pihole):
|
||||||
expected_stdout = 'No active firewall detected'
|
expected_stdout = 'No active firewall detected'
|
||||||
assert expected_stdout in configureFirewall.stdout
|
assert expected_stdout in configureFirewall.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_configureFirewall_IPTables_enabled_declined_no_errors(Pihole):
|
def test_configureFirewall_IPTables_enabled_declined_no_errors(Pihole):
|
||||||
''' confirms IPTables rules are not applied when IPTables is running, user declines ruleset '''
|
'''
|
||||||
|
confirms IPTables rules are not applied when IPTables is running, user
|
||||||
|
declines ruleset
|
||||||
|
'''
|
||||||
# iptables command exists
|
# iptables command exists
|
||||||
mock_command('iptables', {'*':('', '0')}, Pihole)
|
mock_command('iptables', {'*': ('', '0')}, Pihole)
|
||||||
# modinfo returns always true (ip_tables module check)
|
# modinfo returns always true (ip_tables module check)
|
||||||
mock_command('modinfo', {'*':('', '0')}, Pihole)
|
mock_command('modinfo', {'*': ('', '0')}, Pihole)
|
||||||
# Whiptail dialog returns Cancel for user prompt
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
mock_command('whiptail', {'*':('', '1')}, Pihole)
|
mock_command('whiptail', {'*': ('', '1')}, Pihole)
|
||||||
configureFirewall = Pihole.run('''
|
configureFirewall = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
configureFirewall
|
configureFirewall
|
||||||
|
@ -135,14 +174,19 @@ def test_configureFirewall_IPTables_enabled_declined_no_errors(Pihole):
|
||||||
expected_stdout = 'Not installing firewall rulesets.'
|
expected_stdout = 'Not installing firewall rulesets.'
|
||||||
assert expected_stdout in configureFirewall.stdout
|
assert expected_stdout in configureFirewall.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_configureFirewall_IPTables_enabled_rules_exist_no_errors(Pihole):
|
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)
|
confirms IPTables rules are not applied when IPTables is running and rules
|
||||||
mock_command('iptables', {'-S':('-P INPUT DENY', '0')}, Pihole)
|
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)
|
# modinfo returns always true (ip_tables module check)
|
||||||
mock_command('modinfo', {'*':('', '0')}, Pihole)
|
mock_command('modinfo', {'*': ('', '0')}, Pihole)
|
||||||
# Whiptail dialog returns Cancel for user prompt
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
mock_command('whiptail', {'*':('', '0')}, Pihole)
|
mock_command('whiptail', {'*': ('', '0')}, Pihole)
|
||||||
configureFirewall = Pihole.run('''
|
configureFirewall = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
configureFirewall
|
configureFirewall
|
||||||
|
@ -150,18 +194,46 @@ def test_configureFirewall_IPTables_enabled_rules_exist_no_errors(Pihole):
|
||||||
expected_stdout = 'Installing new IPTables firewall rulesets'
|
expected_stdout = 'Installing new IPTables firewall rulesets'
|
||||||
assert expected_stdout in configureFirewall.stdout
|
assert expected_stdout in configureFirewall.stdout
|
||||||
firewall_calls = Pihole.run('cat /var/log/iptables').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
|
# General call type occurances
|
||||||
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT' not in firewall_calls
|
assert len(re.findall(r'iptables -S', firewall_calls)) == 1
|
||||||
assert 'iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT' not in firewall_calls
|
assert len(re.findall(r'iptables -C', firewall_calls)) == 4
|
||||||
|
assert len(re.findall(r'iptables -I', firewall_calls)) == 0
|
||||||
|
|
||||||
|
# Specific port call occurances
|
||||||
|
assert len(re.findall(r'tcp --dport 80', firewall_calls)) == 1
|
||||||
|
assert len(re.findall(r'tcp --dport 53', firewall_calls)) == 1
|
||||||
|
assert len(re.findall(r'udp --dport 53', firewall_calls)) == 1
|
||||||
|
assert len(re.findall(r'tcp --dport 4711:4720', firewall_calls)) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_configureFirewall_IPTables_enabled_not_exist_no_errors(Pihole):
|
def test_configureFirewall_IPTables_enabled_not_exist_no_errors(Pihole):
|
||||||
''' confirms IPTables rules are applied when IPTables is running and rules do not exist '''
|
'''
|
||||||
|
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)
|
# 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)
|
mock_command(
|
||||||
|
'iptables',
|
||||||
|
{
|
||||||
|
'-S': (
|
||||||
|
'-P INPUT DENY',
|
||||||
|
'0'
|
||||||
|
),
|
||||||
|
'-C': (
|
||||||
|
'',
|
||||||
|
1
|
||||||
|
),
|
||||||
|
'-I': (
|
||||||
|
'',
|
||||||
|
0
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Pihole
|
||||||
|
)
|
||||||
# modinfo returns always true (ip_tables module check)
|
# modinfo returns always true (ip_tables module check)
|
||||||
mock_command('modinfo', {'*':('', '0')}, Pihole)
|
mock_command('modinfo', {'*': ('', '0')}, Pihole)
|
||||||
# Whiptail dialog returns Cancel for user prompt
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
mock_command('whiptail', {'*':('', '0')}, Pihole)
|
mock_command('whiptail', {'*': ('', '0')}, Pihole)
|
||||||
configureFirewall = Pihole.run('''
|
configureFirewall = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
configureFirewall
|
configureFirewall
|
||||||
|
@ -169,52 +241,160 @@ def test_configureFirewall_IPTables_enabled_not_exist_no_errors(Pihole):
|
||||||
expected_stdout = 'Installing new IPTables firewall rulesets'
|
expected_stdout = 'Installing new IPTables firewall rulesets'
|
||||||
assert expected_stdout in configureFirewall.stdout
|
assert expected_stdout in configureFirewall.stdout
|
||||||
firewall_calls = Pihole.run('cat /var/log/iptables').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
|
# General call type occurances
|
||||||
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT' in firewall_calls
|
assert len(re.findall(r'iptables -S', firewall_calls)) == 1
|
||||||
assert 'iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT' in firewall_calls
|
assert len(re.findall(r'iptables -C', firewall_calls)) == 4
|
||||||
|
assert len(re.findall(r'iptables -I', firewall_calls)) == 4
|
||||||
|
|
||||||
|
# Specific port call occurances
|
||||||
|
assert len(re.findall(r'tcp --dport 80', firewall_calls)) == 2
|
||||||
|
assert len(re.findall(r'tcp --dport 53', firewall_calls)) == 2
|
||||||
|
assert len(re.findall(r'udp --dport 53', firewall_calls)) == 2
|
||||||
|
assert len(re.findall(r'tcp --dport 4711:4720', firewall_calls)) == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_selinux_enforcing_default_exit(Pihole):
|
||||||
|
'''
|
||||||
|
confirms installer prompts to exit when SELinux is Enforcing by default
|
||||||
|
'''
|
||||||
|
# getenforce returns the running state of SELinux
|
||||||
|
mock_command('getenforce', {'*': ('Enforcing', '0')}, Pihole)
|
||||||
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '1')}, Pihole)
|
||||||
|
check_selinux = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
checkSelinux
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + ' SELinux mode detected: Enforcing'
|
||||||
|
assert expected_stdout in check_selinux.stdout
|
||||||
|
expected_stdout = 'SELinux Enforcing detected, exiting installer'
|
||||||
|
assert expected_stdout in check_selinux.stdout
|
||||||
|
assert check_selinux.rc == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_selinux_enforcing_continue(Pihole):
|
||||||
|
'''
|
||||||
|
confirms installer prompts to continue with custom policy warning
|
||||||
|
'''
|
||||||
|
# getenforce returns the running state of SELinux
|
||||||
|
mock_command('getenforce', {'*': ('Enforcing', '0')}, Pihole)
|
||||||
|
# Whiptail dialog returns Continue for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '0')}, Pihole)
|
||||||
|
check_selinux = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
checkSelinux
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + ' SELinux mode detected: Enforcing'
|
||||||
|
assert expected_stdout in check_selinux.stdout
|
||||||
|
expected_stdout = info_box + (' Continuing installation with SELinux '
|
||||||
|
'Enforcing')
|
||||||
|
assert expected_stdout in check_selinux.stdout
|
||||||
|
expected_stdout = info_box + (' Please refer to official SELinux '
|
||||||
|
'documentation to create a custom policy')
|
||||||
|
assert expected_stdout in check_selinux.stdout
|
||||||
|
assert check_selinux.rc == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_selinux_permissive(Pihole):
|
||||||
|
'''
|
||||||
|
confirms installer continues when SELinux is Permissive
|
||||||
|
'''
|
||||||
|
# getenforce returns the running state of SELinux
|
||||||
|
mock_command('getenforce', {'*': ('Permissive', '0')}, Pihole)
|
||||||
|
check_selinux = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
checkSelinux
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + ' SELinux mode detected: Permissive'
|
||||||
|
assert expected_stdout in check_selinux.stdout
|
||||||
|
assert check_selinux.rc == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_selinux_disabled(Pihole):
|
||||||
|
'''
|
||||||
|
confirms installer continues when SELinux is Disabled
|
||||||
|
'''
|
||||||
|
mock_command('getenforce', {'*': ('Disabled', '0')}, Pihole)
|
||||||
|
check_selinux = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
checkSelinux
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + ' SELinux mode detected: Disabled'
|
||||||
|
assert expected_stdout in check_selinux.stdout
|
||||||
|
assert check_selinux.rc == 0
|
||||||
|
|
||||||
|
|
||||||
def test_installPiholeWeb_fresh_install_no_errors(Pihole):
|
def test_installPiholeWeb_fresh_install_no_errors(Pihole):
|
||||||
''' confirms all web page assets from Core repo are installed on a fresh build '''
|
'''
|
||||||
|
confirms all web page assets from Core repo are installed on a fresh build
|
||||||
|
'''
|
||||||
installWeb = Pihole.run('''
|
installWeb = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
installPiholeWeb
|
installPiholeWeb
|
||||||
''')
|
''')
|
||||||
assert info_box + ' Installing blocking page...' in installWeb.stdout
|
expected_stdout = info_box + ' Installing blocking page...'
|
||||||
assert tick_box + ' Creating directory for blocking page, and copying files' in installWeb.stdout
|
assert expected_stdout in installWeb.stdout
|
||||||
assert cross_box + ' Backing up index.lighttpd.html' in installWeb.stdout
|
expected_stdout = tick_box + (' Creating directory for blocking page, '
|
||||||
assert 'No default index.lighttpd.html file found... not backing up' in installWeb.stdout
|
'and copying files')
|
||||||
assert tick_box + ' Installing sudoer file' in installWeb.stdout
|
assert expected_stdout in installWeb.stdout
|
||||||
|
expected_stdout = cross_box + ' Backing up index.lighttpd.html'
|
||||||
|
assert expected_stdout in installWeb.stdout
|
||||||
|
expected_stdout = ('No default index.lighttpd.html file found... '
|
||||||
|
'not backing up')
|
||||||
|
assert expected_stdout in installWeb.stdout
|
||||||
|
expected_stdout = tick_box + ' Installing sudoer file'
|
||||||
|
assert expected_stdout in installWeb.stdout
|
||||||
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
|
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
|
||||||
assert 'index.php' in web_directory
|
assert 'index.php' in web_directory
|
||||||
assert 'blockingpage.css' in web_directory
|
assert 'blockingpage.css' in web_directory
|
||||||
|
|
||||||
|
|
||||||
def test_update_package_cache_success_no_errors(Pihole):
|
def test_update_package_cache_success_no_errors(Pihole):
|
||||||
''' confirms package cache was updated without any errors'''
|
'''
|
||||||
|
confirms package cache was updated without any errors
|
||||||
|
'''
|
||||||
updateCache = Pihole.run('''
|
updateCache = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
distro_check
|
distro_check
|
||||||
update_package_cache
|
update_package_cache
|
||||||
''')
|
''')
|
||||||
assert tick_box + ' Update local cache of available packages' in updateCache.stdout
|
expected_stdout = tick_box + ' Update local cache of available packages'
|
||||||
assert 'Error: Unable to update package cache.' not in updateCache.stdout
|
assert expected_stdout in updateCache.stdout
|
||||||
|
assert 'error' not in updateCache.stdout.lower()
|
||||||
|
|
||||||
|
|
||||||
def test_update_package_cache_failure_no_errors(Pihole):
|
def test_update_package_cache_failure_no_errors(Pihole):
|
||||||
''' confirms package cache was not updated'''
|
'''
|
||||||
mock_command('apt-get', {'update':('', '1')}, Pihole)
|
confirms package cache was not updated
|
||||||
|
'''
|
||||||
|
mock_command('apt-get', {'update': ('', '1')}, Pihole)
|
||||||
updateCache = Pihole.run('''
|
updateCache = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
distro_check
|
distro_check
|
||||||
update_package_cache
|
update_package_cache
|
||||||
''')
|
''')
|
||||||
assert cross_box + ' Update local cache of available packages' in updateCache.stdout
|
expected_stdout = cross_box + ' Update local cache of available packages'
|
||||||
|
assert expected_stdout in updateCache.stdout
|
||||||
assert 'Error: Unable to update package cache.' in updateCache.stdout
|
assert 'Error: Unable to update package cache.' in updateCache.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_FTL_detect_aarch64_no_errors(Pihole):
|
def test_FTL_detect_aarch64_no_errors(Pihole):
|
||||||
''' confirms only aarch64 package is downloaded for FTL engine '''
|
'''
|
||||||
|
confirms only aarch64 package is downloaded for FTL engine
|
||||||
|
'''
|
||||||
# mock uname to return aarch64 platform
|
# mock uname to return aarch64 platform
|
||||||
mock_command('uname', {'-m':('aarch64', '0')}, Pihole)
|
mock_command('uname', {'-m': ('aarch64', '0')}, Pihole)
|
||||||
# mock ldd to respond with aarch64 shared library
|
# mock ldd to respond with aarch64 shared library
|
||||||
mock_command('ldd', {'/bin/ls':('/lib/ld-linux-aarch64.so.1', '0')}, Pihole)
|
mock_command(
|
||||||
|
'ldd',
|
||||||
|
{
|
||||||
|
'/bin/ls': (
|
||||||
|
'/lib/ld-linux-aarch64.so.1',
|
||||||
|
'0'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Pihole
|
||||||
|
)
|
||||||
detectPlatform = Pihole.run('''
|
detectPlatform = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
FTLdetect
|
FTLdetect
|
||||||
|
@ -226,29 +406,36 @@ def test_FTL_detect_aarch64_no_errors(Pihole):
|
||||||
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
||||||
assert expected_stdout in detectPlatform.stdout
|
assert expected_stdout in detectPlatform.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_FTL_detect_armv6l_no_errors(Pihole):
|
def test_FTL_detect_armv6l_no_errors(Pihole):
|
||||||
''' confirms only armv6l package is downloaded for FTL engine '''
|
'''
|
||||||
|
confirms only armv6l package is downloaded for FTL engine
|
||||||
|
'''
|
||||||
# mock uname to return armv6l platform
|
# mock uname to return armv6l platform
|
||||||
mock_command('uname', {'-m':('armv6l', '0')}, Pihole)
|
mock_command('uname', {'-m': ('armv6l', '0')}, Pihole)
|
||||||
# mock ldd to respond with aarch64 shared library
|
# mock ldd to respond with aarch64 shared library
|
||||||
mock_command('ldd', {'/bin/ls':('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
|
mock_command('ldd', {'/bin/ls': ('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
|
||||||
detectPlatform = Pihole.run('''
|
detectPlatform = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
FTLdetect
|
FTLdetect
|
||||||
''')
|
''')
|
||||||
expected_stdout = info_box + ' FTL Checks...'
|
expected_stdout = info_box + ' FTL Checks...'
|
||||||
assert expected_stdout in detectPlatform.stdout
|
assert expected_stdout in detectPlatform.stdout
|
||||||
expected_stdout = tick_box + ' Detected ARM-hf architecture (armv6 or lower)'
|
expected_stdout = tick_box + (' Detected ARM-hf architecture '
|
||||||
|
'(armv6 or lower)')
|
||||||
assert expected_stdout in detectPlatform.stdout
|
assert expected_stdout in detectPlatform.stdout
|
||||||
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
||||||
assert expected_stdout in detectPlatform.stdout
|
assert expected_stdout in detectPlatform.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_FTL_detect_armv7l_no_errors(Pihole):
|
def test_FTL_detect_armv7l_no_errors(Pihole):
|
||||||
''' confirms only armv7l package is downloaded for FTL engine '''
|
'''
|
||||||
|
confirms only armv7l package is downloaded for FTL engine
|
||||||
|
'''
|
||||||
# mock uname to return armv7l platform
|
# mock uname to return armv7l platform
|
||||||
mock_command('uname', {'-m':('armv7l', '0')}, Pihole)
|
mock_command('uname', {'-m': ('armv7l', '0')}, Pihole)
|
||||||
# mock ldd to respond with aarch64 shared library
|
# mock ldd to respond with aarch64 shared library
|
||||||
mock_command('ldd', {'/bin/ls':('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
|
mock_command('ldd', {'/bin/ls': ('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
|
||||||
detectPlatform = Pihole.run('''
|
detectPlatform = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
FTLdetect
|
FTLdetect
|
||||||
|
@ -260,8 +447,11 @@ def test_FTL_detect_armv7l_no_errors(Pihole):
|
||||||
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
||||||
assert expected_stdout in detectPlatform.stdout
|
assert expected_stdout in detectPlatform.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_FTL_detect_x86_64_no_errors(Pihole):
|
def test_FTL_detect_x86_64_no_errors(Pihole):
|
||||||
''' confirms only x86_64 package is downloaded for FTL engine '''
|
'''
|
||||||
|
confirms only x86_64 package is downloaded for FTL engine
|
||||||
|
'''
|
||||||
detectPlatform = Pihole.run('''
|
detectPlatform = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
FTLdetect
|
FTLdetect
|
||||||
|
@ -273,10 +463,11 @@ def test_FTL_detect_x86_64_no_errors(Pihole):
|
||||||
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
||||||
assert expected_stdout in detectPlatform.stdout
|
assert expected_stdout in detectPlatform.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_FTL_detect_unknown_no_errors(Pihole):
|
def test_FTL_detect_unknown_no_errors(Pihole):
|
||||||
''' confirms only generic package is downloaded for FTL engine '''
|
''' confirms only generic package is downloaded for FTL engine '''
|
||||||
# mock uname to return generic platform
|
# mock uname to return generic platform
|
||||||
mock_command('uname', {'-m':('mips', '0')}, Pihole)
|
mock_command('uname', {'-m': ('mips', '0')}, Pihole)
|
||||||
detectPlatform = Pihole.run('''
|
detectPlatform = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
FTLdetect
|
FTLdetect
|
||||||
|
@ -284,8 +475,11 @@ def test_FTL_detect_unknown_no_errors(Pihole):
|
||||||
expected_stdout = 'Not able to detect architecture (unknown: mips)'
|
expected_stdout = 'Not able to detect architecture (unknown: mips)'
|
||||||
assert expected_stdout in detectPlatform.stdout
|
assert expected_stdout in detectPlatform.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_FTL_download_aarch64_no_errors(Pihole):
|
def test_FTL_download_aarch64_no_errors(Pihole):
|
||||||
''' confirms only aarch64 package is downloaded for FTL engine '''
|
'''
|
||||||
|
confirms only aarch64 package is downloaded for FTL engine
|
||||||
|
'''
|
||||||
# mock uname to return generic platform
|
# mock uname to return generic platform
|
||||||
download_binary = Pihole.run('''
|
download_binary = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
|
@ -293,13 +487,13 @@ def test_FTL_download_aarch64_no_errors(Pihole):
|
||||||
''')
|
''')
|
||||||
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
expected_stdout = tick_box + ' Downloading and Installing FTL'
|
||||||
assert expected_stdout in download_binary.stdout
|
assert expected_stdout in download_binary.stdout
|
||||||
error = 'Error: Download of binary from Github failed'
|
assert 'error' not in download_binary.stdout.lower()
|
||||||
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):
|
def test_FTL_download_unknown_fails_no_errors(Pihole):
|
||||||
''' confirms unknown binary is not downloaded for FTL engine '''
|
'''
|
||||||
|
confirms unknown binary is not downloaded for FTL engine
|
||||||
|
'''
|
||||||
# mock uname to return generic platform
|
# mock uname to return generic platform
|
||||||
download_binary = Pihole.run('''
|
download_binary = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
|
@ -310,8 +504,11 @@ def test_FTL_download_unknown_fails_no_errors(Pihole):
|
||||||
error = 'Error: URL not found'
|
error = 'Error: URL not found'
|
||||||
assert error in download_binary.stdout
|
assert error in download_binary.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_FTL_binary_installed_and_responsive_no_errors(Pihole):
|
def test_FTL_binary_installed_and_responsive_no_errors(Pihole):
|
||||||
''' confirms FTL binary is copied and functional in installed location '''
|
'''
|
||||||
|
confirms FTL binary is copied and functional in installed location
|
||||||
|
'''
|
||||||
installed_binary = Pihole.run('''
|
installed_binary = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
FTLdetect
|
FTLdetect
|
||||||
|
@ -320,8 +517,11 @@ def test_FTL_binary_installed_and_responsive_no_errors(Pihole):
|
||||||
expected_stdout = 'v'
|
expected_stdout = 'v'
|
||||||
assert expected_stdout in installed_binary.stdout
|
assert expected_stdout in installed_binary.stdout
|
||||||
|
|
||||||
|
|
||||||
# def test_FTL_support_files_installed(Pihole):
|
# def test_FTL_support_files_installed(Pihole):
|
||||||
# ''' confirms FTL support files are installed '''
|
# '''
|
||||||
|
# confirms FTL support files are installed
|
||||||
|
# '''
|
||||||
# support_files = Pihole.run('''
|
# support_files = Pihole.run('''
|
||||||
# source /opt/pihole/basic-install.sh
|
# source /opt/pihole/basic-install.sh
|
||||||
# FTLdetect
|
# FTLdetect
|
||||||
|
@ -334,21 +534,46 @@ def test_FTL_binary_installed_and_responsive_no_errors(Pihole):
|
||||||
# assert '644 /run/pihole-FTL.pid' 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
|
# assert '644 /var/log/pihole-FTL.log' in support_files.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_IPv6_only_link_local(Pihole):
|
def test_IPv6_only_link_local(Pihole):
|
||||||
''' confirms IPv6 blocking is disabled for Link-local address '''
|
'''
|
||||||
|
confirms IPv6 blocking is disabled for Link-local address
|
||||||
|
'''
|
||||||
# mock ip -6 address to return 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)
|
mock_command_2(
|
||||||
|
'ip',
|
||||||
|
{
|
||||||
|
'-6 address': (
|
||||||
|
'inet6 fe80::d210:52fa:fe00:7ad7/64 scope link',
|
||||||
|
'0'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Pihole
|
||||||
|
)
|
||||||
detectPlatform = Pihole.run('''
|
detectPlatform = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
useIPv6dialog
|
useIPv6dialog
|
||||||
''')
|
''')
|
||||||
expected_stdout = 'Unable to find IPv6 ULA/GUA address, IPv6 adblocking will not be enabled'
|
expected_stdout = ('Unable to find IPv6 ULA/GUA address, '
|
||||||
|
'IPv6 adblocking will not be enabled')
|
||||||
assert expected_stdout in detectPlatform.stdout
|
assert expected_stdout in detectPlatform.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_IPv6_only_ULA(Pihole):
|
def test_IPv6_only_ULA(Pihole):
|
||||||
''' confirms IPv6 blocking is enabled for ULA addresses '''
|
'''
|
||||||
|
confirms IPv6 blocking is enabled for ULA addresses
|
||||||
|
'''
|
||||||
# mock ip -6 address to return ULA address
|
# 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)
|
mock_command_2(
|
||||||
|
'ip',
|
||||||
|
{
|
||||||
|
'-6 address': (
|
||||||
|
'inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global',
|
||||||
|
'0'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Pihole
|
||||||
|
)
|
||||||
detectPlatform = Pihole.run('''
|
detectPlatform = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
useIPv6dialog
|
useIPv6dialog
|
||||||
|
@ -356,10 +581,22 @@ def test_IPv6_only_ULA(Pihole):
|
||||||
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
||||||
assert expected_stdout in detectPlatform.stdout
|
assert expected_stdout in detectPlatform.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_IPv6_only_GUA(Pihole):
|
def test_IPv6_only_GUA(Pihole):
|
||||||
''' confirms IPv6 blocking is enabled for GUA addresses '''
|
'''
|
||||||
|
confirms IPv6 blocking is enabled for GUA addresses
|
||||||
|
'''
|
||||||
# mock ip -6 address to return GUA address
|
# 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)
|
mock_command_2(
|
||||||
|
'ip',
|
||||||
|
{
|
||||||
|
'-6 address': (
|
||||||
|
'inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global',
|
||||||
|
'0'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Pihole
|
||||||
|
)
|
||||||
detectPlatform = Pihole.run('''
|
detectPlatform = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
useIPv6dialog
|
useIPv6dialog
|
||||||
|
@ -367,10 +604,23 @@ def test_IPv6_only_GUA(Pihole):
|
||||||
expected_stdout = 'Found IPv6 GUA address, using it for blocking IPv6 ads'
|
expected_stdout = 'Found IPv6 GUA address, using it for blocking IPv6 ads'
|
||||||
assert expected_stdout in detectPlatform.stdout
|
assert expected_stdout in detectPlatform.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_IPv6_GUA_ULA_test(Pihole):
|
def test_IPv6_GUA_ULA_test(Pihole):
|
||||||
''' confirms IPv6 blocking is enabled for GUA and ULA addresses '''
|
'''
|
||||||
|
confirms IPv6 blocking is enabled for GUA and ULA addresses
|
||||||
|
'''
|
||||||
# mock ip -6 address to return 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)
|
mock_command_2(
|
||||||
|
'ip',
|
||||||
|
{
|
||||||
|
'-6 address': (
|
||||||
|
'inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global\n'
|
||||||
|
'inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global',
|
||||||
|
'0'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Pihole
|
||||||
|
)
|
||||||
detectPlatform = Pihole.run('''
|
detectPlatform = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
useIPv6dialog
|
useIPv6dialog
|
||||||
|
@ -378,61 +628,26 @@ def test_IPv6_GUA_ULA_test(Pihole):
|
||||||
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
||||||
assert expected_stdout in detectPlatform.stdout
|
assert expected_stdout in detectPlatform.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_IPv6_ULA_GUA_test(Pihole):
|
def test_IPv6_ULA_GUA_test(Pihole):
|
||||||
''' confirms IPv6 blocking is enabled for GUA and ULA addresses '''
|
'''
|
||||||
|
confirms IPv6 blocking is enabled for GUA and ULA addresses
|
||||||
|
'''
|
||||||
# mock ip -6 address to return ULA and GUA 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)
|
mock_command_2(
|
||||||
|
'ip',
|
||||||
|
{
|
||||||
|
'-6 address': (
|
||||||
|
'inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global\n'
|
||||||
|
'inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global',
|
||||||
|
'0'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Pihole
|
||||||
|
)
|
||||||
detectPlatform = Pihole.run('''
|
detectPlatform = Pihole.run('''
|
||||||
source /opt/pihole/basic-install.sh
|
source /opt/pihole/basic-install.sh
|
||||||
useIPv6dialog
|
useIPv6dialog
|
||||||
''')
|
''')
|
||||||
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
||||||
assert expected_stdout in detectPlatform.stdout
|
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
|
|
||||||
|
|
209
test/test_centos_fedora_support.py
Normal file
209
test/test_centos_fedora_support.py
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
import pytest
|
||||||
|
from conftest import (
|
||||||
|
tick_box,
|
||||||
|
info_box,
|
||||||
|
cross_box,
|
||||||
|
mock_command,
|
||||||
|
mock_command_2,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("tag", [('fedora'), ])
|
||||||
|
def test_epel_and_remi_not_installed_fedora(Pihole):
|
||||||
|
'''
|
||||||
|
confirms installer does not attempt to install EPEL/REMI repositories
|
||||||
|
on Fedora
|
||||||
|
'''
|
||||||
|
distro_check = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
distro_check
|
||||||
|
''')
|
||||||
|
assert distro_check.stdout == ''
|
||||||
|
|
||||||
|
epel_package = Pihole.package('epel-release')
|
||||||
|
assert not epel_package.is_installed
|
||||||
|
remi_package = Pihole.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||||
|
def test_release_supported_version_check_centos(Pihole):
|
||||||
|
'''
|
||||||
|
confirms installer exits on unsupported releases of CentOS
|
||||||
|
'''
|
||||||
|
# mock CentOS release < 7 (unsupported)
|
||||||
|
mock_command_2(
|
||||||
|
'rpm',
|
||||||
|
{"-q --queryformat '%{VERSION}' centos-release'": (
|
||||||
|
'5',
|
||||||
|
'0'
|
||||||
|
)},
|
||||||
|
Pihole
|
||||||
|
)
|
||||||
|
distro_check = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
distro_check
|
||||||
|
''')
|
||||||
|
expected_stdout = cross_box + (' CentOS is not suported.')
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
expected_stdout = 'Please update to CentOS release 7 or later'
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||||
|
def test_enable_epel_repository_centos(Pihole):
|
||||||
|
'''
|
||||||
|
confirms the EPEL package repository is enabled when installed on CentOS
|
||||||
|
'''
|
||||||
|
distro_check = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
distro_check
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' Enabling EPEL package repository '
|
||||||
|
'(https://fedoraproject.org/wiki/EPEL)')
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
expected_stdout = tick_box + ' Installed epel-release'
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
epel_package = Pihole.package('epel-release')
|
||||||
|
assert epel_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||||
|
def test_php_upgrade_default_optout_centos(Pihole):
|
||||||
|
'''
|
||||||
|
confirms the default behavior to opt-out of installing PHP7 from REMI
|
||||||
|
'''
|
||||||
|
distro_check = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
distro_check
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
|
'Deprecated PHP may be in use.')
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
remi_package = Pihole.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||||
|
def test_php_upgrade_user_optout_centos(Pihole):
|
||||||
|
'''
|
||||||
|
confirms installer behavior when user opt-out of installing PHP7 from REMI
|
||||||
|
(php not currently installed)
|
||||||
|
'''
|
||||||
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '1')}, Pihole)
|
||||||
|
distro_check = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
distro_check
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
|
'Deprecated PHP may be in use.')
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
remi_package = Pihole.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||||
|
def test_php_upgrade_user_optin_centos(Pihole):
|
||||||
|
'''
|
||||||
|
confirms installer behavior when user opt-in to installing PHP7 from REMI
|
||||||
|
(php not currently installed)
|
||||||
|
'''
|
||||||
|
# Whiptail dialog returns Continue for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '0')}, Pihole)
|
||||||
|
distro_check = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
distro_check
|
||||||
|
''')
|
||||||
|
assert 'opt-out' not in distro_check.stdout
|
||||||
|
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||||
|
'(https://rpms.remirepo.net)')
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||||
|
'been enabled for PHP7')
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
remi_package = Pihole.package('remi-release')
|
||||||
|
assert remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||||
|
def test_php_version_lt_7_detected_upgrade_default_optout_centos(Pihole):
|
||||||
|
'''
|
||||||
|
confirms the default behavior to opt-out of upgrading to PHP7 from REMI
|
||||||
|
'''
|
||||||
|
# first we will install the default php version to test installer behavior
|
||||||
|
php_install = Pihole.run('yum install -y php')
|
||||||
|
assert php_install.rc == 0
|
||||||
|
php_package = Pihole.package('php')
|
||||||
|
default_centos_php_version = php_package.version.split('.')[0]
|
||||||
|
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||||
|
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||||
|
distro_check = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
distro_check
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
|
'Deprecated PHP may be in use.')
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
remi_package = Pihole.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||||
|
def test_php_version_lt_7_detected_upgrade_user_optout_centos(Pihole):
|
||||||
|
'''
|
||||||
|
confirms installer behavior when user opt-out to upgrade to PHP7 via REMI
|
||||||
|
'''
|
||||||
|
# first we will install the default php version to test installer behavior
|
||||||
|
php_install = Pihole.run('yum install -y php')
|
||||||
|
assert php_install.rc == 0
|
||||||
|
php_package = Pihole.package('php')
|
||||||
|
default_centos_php_version = php_package.version.split('.')[0]
|
||||||
|
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||||
|
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||||
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '1')}, Pihole)
|
||||||
|
distro_check = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
distro_check
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
|
'Deprecated PHP may be in use.')
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
remi_package = Pihole.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("tag", [('centos'), ])
|
||||||
|
def test_php_version_lt_7_detected_upgrade_user_optin_centos(Pihole):
|
||||||
|
'''
|
||||||
|
confirms installer behavior when user opt-in to upgrade to PHP7 via REMI
|
||||||
|
'''
|
||||||
|
# first we will install the default php version to test installer behavior
|
||||||
|
php_install = Pihole.run('yum install -y php')
|
||||||
|
assert php_install.rc == 0
|
||||||
|
php_package = Pihole.package('php')
|
||||||
|
default_centos_php_version = php_package.version.split('.')[0]
|
||||||
|
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||||
|
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||||
|
# Whiptail dialog returns Continue for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '0')}, Pihole)
|
||||||
|
distro_check = Pihole.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
distro_check
|
||||||
|
install_dependent_packages PIHOLE_WEB_DEPS[@]
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
|
'Deprecated PHP may be in use.')
|
||||||
|
assert expected_stdout not in distro_check.stdout
|
||||||
|
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||||
|
'(https://rpms.remirepo.net)')
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||||
|
'been enabled for PHP7')
|
||||||
|
assert expected_stdout in distro_check.stdout
|
||||||
|
remi_package = Pihole.package('remi-release')
|
||||||
|
assert remi_package.is_installed
|
||||||
|
updated_php_package = Pihole.package('php')
|
||||||
|
updated_php_version = updated_php_package.version.split('.')[0]
|
||||||
|
assert int(updated_php_version) == 7
|
|
@ -1,13 +1,18 @@
|
||||||
import pytest
|
|
||||||
import testinfra
|
import testinfra
|
||||||
|
|
||||||
run_local = testinfra.get_backend(
|
run_local = testinfra.get_backend(
|
||||||
"local://"
|
"local://"
|
||||||
).get_module("Command").run
|
).get_module("Command").run
|
||||||
|
|
||||||
|
|
||||||
def test_scripts_pass_shellcheck():
|
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;"
|
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)
|
results = run_local(shellcheck)
|
||||||
print results.stdout
|
print results.stdout
|
||||||
assert '' == results.stdout
|
assert '' == results.stdout
|
||||||
|
|
10
tox.ini
Normal file
10
tox.ini
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[tox]
|
||||||
|
envlist = py27
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
whitelist_externals = docker
|
||||||
|
deps = -rrequirements.txt
|
||||||
|
commands = docker build -f test/debian.Dockerfile -t pytest_pihole:debian .
|
||||||
|
docker build -f test/centos.Dockerfile -t pytest_pihole:centos .
|
||||||
|
docker build -f test/fedora.Dockerfile -t pytest_pihole:fedora .
|
||||||
|
pytest {posargs:-vv -n auto} -m "not build_stage" ./test/
|
Loading…
Reference in a new issue