mirror of
https://github.com/pi-hole/pi-hole.git
synced 2024-12-25 14:20:18 +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.
|
||||||
|
|
69
README.md
69
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
|
||||||
|
@ -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
|
|
||||||
|
|
|
@ -179,6 +179,7 @@ get_init_stats() {
|
||||||
90009[2-3]|920093) sys_model=" Zero";; # 512MB
|
90009[2-3]|920093) sys_model=" Zero";; # 512MB
|
||||||
9000c1) sys_model=" Zero W";; # 512MB
|
9000c1) sys_model=" Zero W";; # 512MB
|
||||||
a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB
|
a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB
|
||||||
|
a020d3) sys_model=" 3, Model B+";; # 1GB
|
||||||
*) sys_model="";;
|
*) sys_model="";;
|
||||||
esac
|
esac
|
||||||
sys_type="Raspberry Pi$sys_model"
|
sys_type="Raspberry Pi$sys_model"
|
||||||
|
@ -477,10 +478,7 @@ chronoFunc() {
|
||||||
${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC}
|
${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC}
|
||||||
${COL_DARK_GRAY}$scr_line_str${COL_NC}"
|
${COL_DARK_GRAY}$scr_line_str${COL_NC}"
|
||||||
else
|
else
|
||||||
echo -e "[0;1;31;91m|¯[0;1;33;93m¯[0;1;32;92m¯[0;1;32;92m(¯[0;1;36;96m)[0;1;34;94m_[0;1;35;95m|[0;1;33;93m¯[0;1;31;91m|_ [0;1;32;92m__[0;1;36;96m_|[0;1;31;91m¯[0;1;34;94m|[0;1;35;95m__[0;1;31;91m_[0m$phc_ver_str
|
echo -e "[0;1;31;91m|¯[0;1;33;93m¯[0;1;32;92m¯[0;1;32;92m(¯[0;1;36;96m)[0;1;34;94m_[0;1;35;95m|[0;1;33;93m¯[0;1;31;91m|_ [0;1;32;92m__[0;1;36;96m_|[0;1;31;91m¯[0;1;34;94m|[0;1;35;95m__[0;1;31;91m_[0m$phc_ver_str[0;1;33;93m| ¯[0;1;32;92m_[0;1;36;96m/¯[0;1;34;94m|[0;1;35;95m_[0;1;31;91m| [0;1;33;93m' [0;1;32;92m\\/ [0;1;36;96m_ [0;1;34;94m\\ [0;1;35;95m/ [0;1;31;91m-[0;1;33;93m_)[0m$lte_ver_str[0;1;32;92m|_[0;1;36;96m| [0;1;34;94m|_[0;1;35;95m| [0;1;33;93m|_[0;1;32;92m||[0;1;36;96m_\\[0;1;34;94m__[0;1;35;95m_/[0;1;31;91m_\\[0;1;33;93m__[0;1;32;92m_|[0m$ftl_ver_str ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
|
||||||
[0;1;33;93m| ¯[0;1;32;92m_[0;1;36;96m/¯[0;1;34;94m|[0;1;35;95m_[0;1;31;91m| [0;1;33;93m' [0;1;32;92m\\/ [0;1;36;96m_ [0;1;34;94m\\ [0;1;35;95m/ [0;1;31;91m-[0;1;33;93m_)[0m$lte_ver_str
|
|
||||||
[0;1;32;92m|_[0;1;36;96m| [0;1;34;94m|_[0;1;35;95m| [0;1;33;93m|_[0;1;32;92m||[0;1;36;96m_\\[0;1;34;94m__[0;1;35;95m_/[0;1;31;91m_\\[0;1;33;93m__[0;1;32;92m_|[0m$ftl_ver_str
|
|
||||||
${COL_DARK_GRAY}$scr_line_str${COL_NC}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printFunc " Hostname: " "$sys_name" "$host_info"
|
printFunc " Hostname: " "$sys_name" "$host_info"
|
||||||
|
|
|
@ -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=()
|
||||||
|
|
||||||
|
@ -31,9 +32,12 @@ 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"
|
||||||
|
elif [[ "${listMain}" == "${regexlist}" ]]; then
|
||||||
|
param="-regex"
|
||||||
|
type="regex black"
|
||||||
else
|
else
|
||||||
param="b"
|
param="b"
|
||||||
type="black"
|
type="black"
|
||||||
|
@ -57,7 +61,8 @@ 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
|
||||||
|
# The first sed removes any amount of leading dots
|
||||||
echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g"
|
echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,10 +70,14 @@ 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}"
|
||||||
|
else
|
||||||
|
validDomain=$(grep -P "^((-|_)*[a-z\\d]((-|_)*[a-z\\d])*(-|_)*)(\\.(-|_)*([a-z\\d]((-|_)*[a-z\\d])*))*$" <<< "${domain}") # Valid chars check
|
||||||
|
validDomain=$(grep -P "^[^\\.]{1,63}(\\.[^\\.]{1,63})*$" <<< "${validDomain}") # Length of each label
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${validDomain}" ]]; then
|
if [[ -n "${validDomain}" ]]; then
|
||||||
|
@ -94,9 +103,6 @@ PoplistFile() {
|
||||||
if ${addmode}; then
|
if ${addmode}; then
|
||||||
AddDomain "${dom}" "${listMain}"
|
AddDomain "${dom}" "${listMain}"
|
||||||
RemoveDomain "${dom}" "${listAlt}"
|
RemoveDomain "${dom}" "${listAlt}"
|
||||||
if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then
|
|
||||||
RemoveDomain "${dom}" "${wildcardlist}"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
RemoveDomain "${dom}" "${listMain}"
|
RemoveDomain "${dom}" "${listMain}"
|
||||||
fi
|
fi
|
||||||
|
@ -109,7 +115,6 @@ AddDomain() {
|
||||||
|
|
||||||
[[ "${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"
|
||||||
|
@ -121,7 +126,7 @@ AddDomain() {
|
||||||
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
|
||||||
|
@ -131,28 +136,26 @@ AddDomain() {
|
||||||
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
|
fi
|
||||||
elif [[ "${list}" == "${wildcardlist}" ]]; then
|
elif [[ "${list}" == "${regexlist}" ]]; 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"
|
[[ -z "${type}" ]] && type="--wildcard-only"
|
||||||
bool=true
|
bool=true
|
||||||
|
domain="${1}"
|
||||||
|
|
||||||
|
[[ "${wildcard}" == true ]] && domain="(^|\\.)${domain//\./\\.}$"
|
||||||
|
|
||||||
# Is the domain in the list?
|
# Is the domain in the list?
|
||||||
grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
|
# Search only for exactly matching lines
|
||||||
|
grep -Fx "${domain}" "${regexlist}" > /dev/null 2>&1 || bool=false
|
||||||
|
|
||||||
if [[ "${bool}" == false ]]; then
|
if [[ "${bool}" == false ]]; then
|
||||||
if [[ "${verbose}" == true ]]; then
|
if [[ "${verbose}" == true ]]; then
|
||||||
echo -e " ${INFO} Adding $1 to wildcard blacklist..."
|
echo -e " ${INFO} Adding ${domain} to regex list..."
|
||||||
fi
|
fi
|
||||||
reload="restart"
|
reload="restart"
|
||||||
echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}"
|
echo "$domain" >> "${regexlist}"
|
||||||
if [[ "${#IPV6_ADDRESS}" > 0 ]]; then
|
|
||||||
echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
if [[ "${verbose}" == true ]]; then
|
if [[ "${verbose}" == true ]]; then
|
||||||
echo -e " ${INFO} ${1} already exists in wildcard blacklist, no need to add!"
|
echo -e " ${INFO} ${domain} already exists in regex list, no need to add!"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -164,7 +167,6 @@ RemoveDomain() {
|
||||||
|
|
||||||
[[ "${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
|
||||||
|
@ -174,7 +176,7 @@ RemoveDomain() {
|
||||||
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
|
||||||
|
@ -183,20 +185,25 @@ RemoveDomain() {
|
||||||
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
|
fi
|
||||||
elif [[ "${list}" == "${wildcardlist}" ]]; then
|
elif [[ "${list}" == "${regexlist}" ]]; then
|
||||||
[[ -z "${type}" ]] && type="--wildcard-only"
|
[[ -z "${type}" ]] && type="--wildcard-only"
|
||||||
|
domain="${1}"
|
||||||
|
|
||||||
|
[[ "${wildcard}" == true ]] && domain="(^|\\.)${domain//\./\\.}$"
|
||||||
|
|
||||||
bool=true
|
bool=true
|
||||||
# Is it in the list?
|
# Is it in the list?
|
||||||
grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
|
grep -Fx "${domain}" "${regexlist}" > /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 $domain from regex list..."
|
||||||
# /I flag: search case-insensitive
|
local lineNumber
|
||||||
sed -i "/address=\/${domain}/Id" "${list}"
|
lineNumber=$(grep -Fnx "$domain" "${list}" | cut -f1 -d:)
|
||||||
|
sed -i "${lineNumber}d" "${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} ${domain} does not exist in regex list, no need to remove!"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -218,7 +225,7 @@ Displaylist() {
|
||||||
verbose=false
|
verbose=false
|
||||||
echo -e "Displaying $string:\n"
|
echo -e "Displaying $string:\n"
|
||||||
count=1
|
count=1
|
||||||
while IFS= read -r RD; do
|
while IFS= read -r RD || [ -n "${RD}" ]; do
|
||||||
echo " ${count}: ${RD}"
|
echo " ${count}: ${RD}"
|
||||||
count=$((count+1))
|
count=$((count+1))
|
||||||
done < "${listMain}"
|
done < "${listMain}"
|
||||||
|
@ -241,7 +248,8 @@ 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;;
|
||||||
|
"--regex" | "regex" ) listMain="${regexlist}";;
|
||||||
"-nr"| "--noreload" ) reload=false;;
|
"-nr"| "--noreload" ) reload=false;;
|
||||||
"-d" | "--delmode" ) addmode=false;;
|
"-d" | "--delmode" ) addmode=false;;
|
||||||
"-q" | "--quiet" ) verbose=false;;
|
"-q" | "--quiet" ) verbose=false;;
|
||||||
|
|
|
@ -17,180 +17,13 @@ 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"
|
||||||
|
@ -218,21 +51,21 @@ checkout() {
|
||||||
|
|
||||||
# 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
|
fi
|
||||||
if [[ "${INSTALL_WEB}" == "true" ]]; then
|
if [[ "${INSTALL_WEB_INTERFACE}" == "true" ]]; then
|
||||||
if ! is_repo "${webInterfaceDir}" ; then
|
if ! is_repo "${webInterfaceDir}" ; then
|
||||||
echo -e " ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!
|
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}"
|
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "${1}" ]]; then
|
if [[ -z "${1}" ]]; then
|
||||||
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}
|
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}"
|
||||||
Try 'pihole checkout --help' for more information."
|
echo -e " Try 'pihole checkout --help' for more information."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -246,7 +79,7 @@ checkout() {
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${INFO} Pi-hole Core"
|
echo -e " ${INFO} Pi-hole Core"
|
||||||
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core developement branch"; exit 1; }
|
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core developement branch"; exit 1; }
|
||||||
if [[ "${INSTALL_WEB}" == "true" ]]; then
|
if [[ "${INSTALL_WEB_INTERFACE}" == "true" ]]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${INFO} Web interface"
|
echo -e " ${INFO} Web interface"
|
||||||
fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; }
|
fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; }
|
||||||
|
@ -257,13 +90,12 @@ checkout() {
|
||||||
local path
|
local path
|
||||||
path="development/${binary}"
|
path="development/${binary}"
|
||||||
echo "development" > /etc/pihole/ftlbranch
|
echo "development" > /etc/pihole/ftlbranch
|
||||||
FTLinstall "${binary}" "${path}"
|
|
||||||
elif [[ "${1}" == "master" ]] ; then
|
elif [[ "${1}" == "master" ]] ; then
|
||||||
# Shortcut to check out master branches
|
# Shortcut to check out master branches
|
||||||
echo -e " ${INFO} Shortcut \"master\" detected - checking out master branches..."
|
echo -e " ${INFO} Shortcut \"master\" detected - checking out master branches..."
|
||||||
echo -e " ${INFO} Pi-hole core"
|
echo -e " ${INFO} Pi-hole core"
|
||||||
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "master" || { echo " ${CROSS} Unable to pull Core master branch"; exit 1; }
|
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "master" || { echo " ${CROSS} Unable to pull Core master branch"; exit 1; }
|
||||||
if [[ ${INSTALL_WEB} == "true" ]]; then
|
if [[ ${INSTALL_WEB_INTERFACE} == "true" ]]; then
|
||||||
echo -e " ${INFO} Web interface"
|
echo -e " ${INFO} Web interface"
|
||||||
fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; }
|
fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; }
|
||||||
fi
|
fi
|
||||||
|
@ -272,7 +104,6 @@ checkout() {
|
||||||
local path
|
local path
|
||||||
path="master/${binary}"
|
path="master/${binary}"
|
||||||
echo "master" > /etc/pihole/ftlbranch
|
echo "master" > /etc/pihole/ftlbranch
|
||||||
FTLinstall "${binary}" "${path}"
|
|
||||||
elif [[ "${1}" == "core" ]] ; then
|
elif [[ "${1}" == "core" ]] ; then
|
||||||
str="Fetching branches from ${piholeGitUrl}"
|
str="Fetching branches from ${piholeGitUrl}"
|
||||||
echo -ne " ${INFO} $str"
|
echo -ne " ${INFO} $str"
|
||||||
|
@ -283,8 +114,8 @@ checkout() {
|
||||||
corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}"))
|
corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}"))
|
||||||
|
|
||||||
if [[ "${corebranches[*]}" == *"master"* ]]; then
|
if [[ "${corebranches[*]}" == *"master"* ]]; then
|
||||||
echo -e "${OVER} ${TICK} $str
|
echo -e "${OVER} ${TICK} $str"
|
||||||
${INFO} ${#corebranches[@]} branches available for Pi-hole Core"
|
echo -e "${INFO} ${#corebranches[@]} branches available for Pi-hole Core"
|
||||||
else
|
else
|
||||||
# Print STDERR output from get_available_branches
|
# Print STDERR output from get_available_branches
|
||||||
echo -e "${OVER} ${CROSS} $str\\n\\n${corebranches[*]}"
|
echo -e "${OVER} ${CROSS} $str\\n\\n${corebranches[*]}"
|
||||||
|
@ -300,7 +131,7 @@ checkout() {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}"
|
checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}"
|
||||||
elif [[ "${1}" == "web" ]] && [[ "${INSTALL_WEB}" == "true" ]] ; then
|
elif [[ "${1}" == "web" ]] && [[ "${INSTALL_WEB_INTERFACE}" == "true" ]] ; then
|
||||||
str="Fetching branches from ${webInterfaceGitUrl}"
|
str="Fetching branches from ${webInterfaceGitUrl}"
|
||||||
echo -ne " ${INFO} $str"
|
echo -ne " ${INFO} $str"
|
||||||
if ! fully_fetch_repo "${webInterfaceDir}" ; then
|
if ! fully_fetch_repo "${webInterfaceDir}" ; then
|
||||||
|
@ -310,8 +141,8 @@ checkout() {
|
||||||
webbranches=($(get_available_branches "${webInterfaceDir}"))
|
webbranches=($(get_available_branches "${webInterfaceDir}"))
|
||||||
|
|
||||||
if [[ "${webbranches[*]}" == *"master"* ]]; then
|
if [[ "${webbranches[*]}" == *"master"* ]]; then
|
||||||
echo -e "${OVER} ${TICK} $str
|
echo -e "${OVER} ${TICK} $str"
|
||||||
${INFO} ${#webbranches[@]} branches available for Web Admin"
|
echo -e "${INFO} ${#webbranches[@]} branches available for Web Admin"
|
||||||
else
|
else
|
||||||
# Print STDERR output from get_available_branches
|
# Print STDERR output from get_available_branches
|
||||||
echo -e "${OVER} ${CROSS} $str\\n\\n${webbranches[*]}"
|
echo -e "${OVER} ${CROSS} $str\\n\\n${webbranches[*]}"
|
||||||
|
@ -335,7 +166,9 @@ checkout() {
|
||||||
if check_download_exists "$path"; then
|
if check_download_exists "$path"; then
|
||||||
echo " ${TICK} Branch ${2} exists"
|
echo " ${TICK} Branch ${2} exists"
|
||||||
echo "${2}" > /etc/pihole/ftlbranch
|
echo "${2}" > /etc/pihole/ftlbranch
|
||||||
FTLinstall "${binary}" "${path}"
|
FTLinstall "${binary}"
|
||||||
|
start_service pihole-FTL
|
||||||
|
enable_service pihole-FTL
|
||||||
else
|
else
|
||||||
echo " ${CROSS} Requested branch \"${2}\" is not available"
|
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}') )
|
ftlbranches=( $(git ls-remote https://github.com/pi-hole/ftl | grep 'heads' | sed 's/refs\/heads\///;s/ //g' | awk '{print $2}') )
|
||||||
|
@ -350,7 +183,7 @@ checkout() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Force updating everything
|
# Force updating everything
|
||||||
if [[ ( ! "${1}" == "web" && ! "${1}" == "ftl" ) && "${update}" == "true" ]]; then
|
if [[ ! "${1}" == "web" && ! "${1}" == "ftl" ]]; then
|
||||||
echo -e " ${INFO} Running installer to upgrade your installation"
|
echo -e " ${INFO} Running installer to upgrade your installation"
|
||||||
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
|
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
|
||||||
exit 0
|
exit 0
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
# This file is copyright under the latest version of the EUPL.
|
# This file is copyright under the latest version of the EUPL.
|
||||||
# Please see LICENSE file for your rights under this license.
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
|
||||||
# -e option instructs bash to immediately exit if any command [1] has a non-zero exit status
|
# -e option instructs bash to immediately exit if any command [1] has a non-zero exit status
|
||||||
# -u a reference to any variable you haven't previously defined
|
# -u a reference to any variable you haven't previously defined
|
||||||
|
@ -37,7 +38,7 @@ else
|
||||||
TICK="[${COL_GREEN}✓${COL_NC}]"
|
TICK="[${COL_GREEN}✓${COL_NC}]"
|
||||||
CROSS="[${COL_RED}✗${COL_NC}]"
|
CROSS="[${COL_RED}✗${COL_NC}]"
|
||||||
INFO="[i]"
|
INFO="[i]"
|
||||||
OVER="\r\033[K"
|
#OVER="\r\033[K"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OBFUSCATED_PLACEHOLDER="<DOMAIN OBFUSCATED>"
|
OBFUSCATED_PLACEHOLDER="<DOMAIN OBFUSCATED>"
|
||||||
|
@ -74,7 +75,7 @@ WEB_SERVER_LOG_DIRECTORY="${LOG_DIRECTORY}/lighttpd"
|
||||||
WEB_SERVER_CONFIG_DIRECTORY="/etc/lighttpd"
|
WEB_SERVER_CONFIG_DIRECTORY="/etc/lighttpd"
|
||||||
HTML_DIRECTORY="/var/www/html"
|
HTML_DIRECTORY="/var/www/html"
|
||||||
WEB_GIT_DIRECTORY="${HTML_DIRECTORY}/admin"
|
WEB_GIT_DIRECTORY="${HTML_DIRECTORY}/admin"
|
||||||
BLOCK_PAGE_DIRECTORY="${HTML_DIRECTORY}/pihole"
|
#BLOCK_PAGE_DIRECTORY="${HTML_DIRECTORY}/pihole"
|
||||||
|
|
||||||
# Files required by Pi-hole
|
# Files required by Pi-hole
|
||||||
# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684
|
# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684
|
||||||
|
@ -85,14 +86,14 @@ PIHOLE_DHCP_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/02-pihole-dhcp.conf"
|
||||||
PIHOLE_WILDCARD_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/03-wildcard.conf"
|
PIHOLE_WILDCARD_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/03-wildcard.conf"
|
||||||
|
|
||||||
WEB_SERVER_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/lighttpd.conf"
|
WEB_SERVER_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/lighttpd.conf"
|
||||||
WEB_SERVER_CUSTOM_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/external.conf"
|
#WEB_SERVER_CUSTOM_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/external.conf"
|
||||||
|
|
||||||
PIHOLE_DEFAULT_AD_LISTS="${PIHOLE_DIRECTORY}/adlists.default"
|
PIHOLE_DEFAULT_AD_LISTS="${PIHOLE_DIRECTORY}/adlists.default"
|
||||||
PIHOLE_USER_DEFINED_AD_LISTS="${PIHOLE_DIRECTORY}/adlists.list"
|
PIHOLE_USER_DEFINED_AD_LISTS="${PIHOLE_DIRECTORY}/adlists.list"
|
||||||
PIHOLE_BLACKLIST_FILE="${PIHOLE_DIRECTORY}/blacklist.txt"
|
PIHOLE_BLACKLIST_FILE="${PIHOLE_DIRECTORY}/blacklist.txt"
|
||||||
PIHOLE_BLOCKLIST_FILE="${PIHOLE_DIRECTORY}/gravity.list"
|
PIHOLE_BLOCKLIST_FILE="${PIHOLE_DIRECTORY}/gravity.list"
|
||||||
PIHOLE_INSTALL_LOG_FILE="${PIHOLE_DIRECTORY}/install.log"
|
PIHOLE_INSTALL_LOG_FILE="${PIHOLE_DIRECTORY}/install.log"
|
||||||
PIHOLE_RAW_BLOCKLIST_FILES=${PIHOLE_DIRECTORY}/list.*
|
PIHOLE_RAW_BLOCKLIST_FILES="${PIHOLE_DIRECTORY}/list.*"
|
||||||
PIHOLE_LOCAL_HOSTS_FILE="${PIHOLE_DIRECTORY}/local.list"
|
PIHOLE_LOCAL_HOSTS_FILE="${PIHOLE_DIRECTORY}/local.list"
|
||||||
PIHOLE_LOGROTATE_FILE="${PIHOLE_DIRECTORY}/logrotate"
|
PIHOLE_LOGROTATE_FILE="${PIHOLE_DIRECTORY}/logrotate"
|
||||||
PIHOLE_SETUP_VARS_FILE="${PIHOLE_DIRECTORY}/setupVars.conf"
|
PIHOLE_SETUP_VARS_FILE="${PIHOLE_DIRECTORY}/setupVars.conf"
|
||||||
|
@ -105,7 +106,7 @@ FTL_PID="${RUN_DIRECTORY}/pihole-FTL.pid"
|
||||||
FTL_PORT="${RUN_DIRECTORY}/pihole-FTL.port"
|
FTL_PORT="${RUN_DIRECTORY}/pihole-FTL.port"
|
||||||
|
|
||||||
PIHOLE_LOG="${LOG_DIRECTORY}/pihole.log"
|
PIHOLE_LOG="${LOG_DIRECTORY}/pihole.log"
|
||||||
PIHOLE_LOG_GZIPS=${LOG_DIRECTORY}/pihole.log.[0-9].*
|
PIHOLE_LOG_GZIPS="${LOG_DIRECTORY}/pihole.log.[0-9].*"
|
||||||
PIHOLE_DEBUG_LOG="${LOG_DIRECTORY}/pihole_debug.log"
|
PIHOLE_DEBUG_LOG="${LOG_DIRECTORY}/pihole_debug.log"
|
||||||
PIHOLE_DEBUG_LOG_SANITIZED="${LOG_DIRECTORY}/pihole_debug-sanitized.log"
|
PIHOLE_DEBUG_LOG_SANITIZED="${LOG_DIRECTORY}/pihole_debug-sanitized.log"
|
||||||
PIHOLE_FTL_LOG="${LOG_DIRECTORY}/pihole-FTL.log"
|
PIHOLE_FTL_LOG="${LOG_DIRECTORY}/pihole-FTL.log"
|
||||||
|
@ -115,53 +116,52 @@ PIHOLE_WEB_SERVER_ERROR_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/error.log"
|
||||||
|
|
||||||
# An array of operating system "pretty names" that we officialy support
|
# An array of operating system "pretty names" that we officialy support
|
||||||
# We can loop through the array at any time to see if it matches a value
|
# We can loop through the array at any time to see if it matches a value
|
||||||
SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS")
|
#SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS")
|
||||||
|
|
||||||
# Store Pi-hole's processes in an array for easy use and parsing
|
# Store Pi-hole's processes in an array for easy use and parsing
|
||||||
PIHOLE_PROCESSES=( "dnsmasq" "lighttpd" "pihole-FTL" )
|
PIHOLE_PROCESSES=( "dnsmasq" "lighttpd" "pihole-FTL" )
|
||||||
|
|
||||||
# Store the required directories in an array so it can be parsed through
|
# Store the required directories in an array so it can be parsed through
|
||||||
REQUIRED_DIRECTORIES=(${CORE_GIT_DIRECTORY}
|
#REQUIRED_DIRECTORIES=("${CORE_GIT_DIRECTORY}"
|
||||||
${CRON_D_DIRECTORY}
|
#"${CRON_D_DIRECTORY}"
|
||||||
${DNSMASQ_D_DIRECTORY}
|
#"${DNSMASQ_D_DIRECTORY}"
|
||||||
${PIHOLE_DIRECTORY}
|
#"${PIHOLE_DIRECTORY}"
|
||||||
${PIHOLE_SCRIPTS_DIRECTORY}
|
#"${PIHOLE_SCRIPTS_DIRECTORY}"
|
||||||
${BIN_DIRECTORY}
|
#"${BIN_DIRECTORY}"
|
||||||
${RUN_DIRECTORY}
|
#"${RUN_DIRECTORY}"
|
||||||
${LOG_DIRECTORY}
|
#"${LOG_DIRECTORY}"
|
||||||
${WEB_SERVER_LOG_DIRECTORY}
|
#"${WEB_SERVER_LOG_DIRECTORY}"
|
||||||
${WEB_SERVER_CONFIG_DIRECTORY}
|
#"${WEB_SERVER_CONFIG_DIRECTORY}"
|
||||||
${HTML_DIRECTORY}
|
#"${HTML_DIRECTORY}"
|
||||||
${WEB_GIT_DIRECTORY}
|
#"${WEB_GIT_DIRECTORY}"
|
||||||
${BLOCK_PAGE_DIRECTORY})
|
#"${BLOCK_PAGE_DIRECTORY}")
|
||||||
|
|
||||||
# Store the required directories in an array so it can be parsed through
|
# Store the required directories in an array so it can be parsed through
|
||||||
mapfile -t array <<< "$var"
|
REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
|
||||||
REQUIRED_FILES=(${PIHOLE_CRON_FILE}
|
"${PIHOLE_DNS_CONFIG_FILE}"
|
||||||
${PIHOLE_DNS_CONFIG_FILE}
|
"${PIHOLE_DHCP_CONFIG_FILE}"
|
||||||
${PIHOLE_DHCP_CONFIG_FILE}
|
"${PIHOLE_WILDCARD_CONFIG_FILE}"
|
||||||
${PIHOLE_WILDCARD_CONFIG_FILE}
|
"${WEB_SERVER_CONFIG_FILE}"
|
||||||
${WEB_SERVER_CONFIG_FILE}
|
"${PIHOLE_DEFAULT_AD_LISTS}"
|
||||||
${PIHOLE_DEFAULT_AD_LISTS}
|
"${PIHOLE_USER_DEFINED_AD_LISTS}"
|
||||||
${PIHOLE_USER_DEFINED_AD_LISTS}
|
"${PIHOLE_BLACKLIST_FILE}"
|
||||||
${PIHOLE_BLACKLIST_FILE}
|
"${PIHOLE_BLOCKLIST_FILE}"
|
||||||
${PIHOLE_BLOCKLIST_FILE}
|
"${PIHOLE_INSTALL_LOG_FILE}"
|
||||||
${PIHOLE_INSTALL_LOG_FILE}
|
"${PIHOLE_RAW_BLOCKLIST_FILES}"
|
||||||
${PIHOLE_RAW_BLOCKLIST_FILES}
|
"${PIHOLE_LOCAL_HOSTS_FILE}"
|
||||||
${PIHOLE_LOCAL_HOSTS_FILE}
|
"${PIHOLE_LOGROTATE_FILE}"
|
||||||
${PIHOLE_LOGROTATE_FILE}
|
"${PIHOLE_SETUP_VARS_FILE}"
|
||||||
${PIHOLE_SETUP_VARS_FILE}
|
"${PIHOLE_WHITELIST_FILE}"
|
||||||
${PIHOLE_WHITELIST_FILE}
|
"${PIHOLE_COMMAND}"
|
||||||
${PIHOLE_COMMAND}
|
"${PIHOLE_COLTABLE_FILE}"
|
||||||
${PIHOLE_COLTABLE_FILE}
|
"${FTL_PID}"
|
||||||
${FTL_PID}
|
"${FTL_PORT}"
|
||||||
${FTL_PORT}
|
"${PIHOLE_LOG}"
|
||||||
${PIHOLE_LOG}
|
"${PIHOLE_LOG_GZIPS}"
|
||||||
${PIHOLE_LOG_GZIPS}
|
"${PIHOLE_DEBUG_LOG}"
|
||||||
${PIHOLE_DEBUG_LOG}
|
"${PIHOLE_FTL_LOG}"
|
||||||
${PIHOLE_FTL_LOG}
|
"${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}"
|
||||||
${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}
|
"${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}")
|
||||||
${PIHOLE_WEB_SERVER_ERROR_LOG_FILE})
|
|
||||||
|
|
||||||
DISCLAIMER="This process collects information from your Pi-hole, and optionally uploads it to a unique and random directory on tricorder.pi-hole.net.
|
DISCLAIMER="This process collects information from your Pi-hole, and optionally uploads it to a unique and random directory on tricorder.pi-hole.net.
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ show_disclaimer(){
|
||||||
|
|
||||||
source_setup_variables() {
|
source_setup_variables() {
|
||||||
# Display the current test that is running
|
# Display the current test that is running
|
||||||
log_write "\n${COL_PURPLE}*** [ INITIALIZING ]${COL_NC} Sourcing setup variables"
|
log_write "\\n${COL_PURPLE}*** [ INITIALIZING ]${COL_NC} Sourcing setup variables"
|
||||||
# If the variable file exists,
|
# If the variable file exists,
|
||||||
if ls "${PIHOLE_SETUP_VARS_FILE}" 1> /dev/null 2>&1; then
|
if ls "${PIHOLE_SETUP_VARS_FILE}" 1> /dev/null 2>&1; then
|
||||||
log_write "${INFO} Sourcing ${PIHOLE_SETUP_VARS_FILE}...";
|
log_write "${INFO} Sourcing ${PIHOLE_SETUP_VARS_FILE}...";
|
||||||
|
@ -231,7 +231,7 @@ initialize_debug() {
|
||||||
echo_current_diagnostic() {
|
echo_current_diagnostic() {
|
||||||
# Colors are used for visually distinguishing each test in the output
|
# Colors are used for visually distinguishing each test in the output
|
||||||
# These colors do not show in the GUI, but the formatting will
|
# These colors do not show in the GUI, but the formatting will
|
||||||
log_write "\n${COL_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}"
|
log_write "\\n${COL_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}"
|
||||||
}
|
}
|
||||||
|
|
||||||
compare_local_version_to_git_version() {
|
compare_local_version_to_git_version() {
|
||||||
|
@ -245,6 +245,7 @@ compare_local_version_to_git_version() {
|
||||||
local search_term="Pi-hole"
|
local search_term="Pi-hole"
|
||||||
elif [[ "${pihole_component}" == "Web" ]]; then
|
elif [[ "${pihole_component}" == "Web" ]]; then
|
||||||
# We need to search for "AdminLTE" so store it in a variable as well
|
# We need to search for "AdminLTE" so store it in a variable as well
|
||||||
|
#shellcheck disable=2034
|
||||||
local search_term="AdminLTE"
|
local search_term="AdminLTE"
|
||||||
fi
|
fi
|
||||||
# Display what we are checking
|
# Display what we are checking
|
||||||
|
@ -365,7 +366,8 @@ check_critical_program_versions() {
|
||||||
is_os_supported() {
|
is_os_supported() {
|
||||||
local os_to_check="${1}"
|
local os_to_check="${1}"
|
||||||
# Strip just the base name of the system using sed
|
# Strip just the base name of the system using sed
|
||||||
the_os=$(echo ${os_to_check} | sed 's/ .*//')
|
# shellcheck disable=SC2001
|
||||||
|
the_os=$(echo "${os_to_check}" | sed 's/ .*//')
|
||||||
# If the variable is one of our supported OSes,
|
# If the variable is one of our supported OSes,
|
||||||
case "${the_os}" in
|
case "${the_os}" in
|
||||||
# Print it in green
|
# Print it in green
|
||||||
|
@ -384,6 +386,8 @@ get_distro_attributes() {
|
||||||
OLD_IFS="$IFS"
|
OLD_IFS="$IFS"
|
||||||
# Store the distro info in an array and make it global since the OS won't change,
|
# Store the distro info in an array and make it global since the OS won't change,
|
||||||
# but we'll keep it within the function for better unit testing
|
# but we'll keep it within the function for better unit testing
|
||||||
|
local distro_info
|
||||||
|
#shellcheck disable=SC2016
|
||||||
IFS=$'\r\n' command eval 'distro_info=( $(cat /etc/*release) )'
|
IFS=$'\r\n' command eval 'distro_info=( $(cat /etc/*release) )'
|
||||||
|
|
||||||
# Set a named variable for better readability
|
# Set a named variable for better readability
|
||||||
|
@ -391,7 +395,8 @@ get_distro_attributes() {
|
||||||
# For each line found in an /etc/*release file,
|
# For each line found in an /etc/*release file,
|
||||||
for distro_attribute in "${distro_info[@]}"; do
|
for distro_attribute in "${distro_info[@]}"; do
|
||||||
# store the key in a variable
|
# store the key in a variable
|
||||||
local pretty_name_key=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f1)
|
local pretty_name_key
|
||||||
|
pretty_name_key=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f1)
|
||||||
# we need just the OS PRETTY_NAME,
|
# we need just the OS PRETTY_NAME,
|
||||||
if [[ "${pretty_name_key}" == "PRETTY_NAME" ]]; then
|
if [[ "${pretty_name_key}" == "PRETTY_NAME" ]]; then
|
||||||
# so save in in a variable when we find it
|
# so save in in a variable when we find it
|
||||||
|
@ -465,15 +470,15 @@ processor_check() {
|
||||||
else
|
else
|
||||||
# Check if the architecture is currently supported for FTL
|
# Check if the architecture is currently supported for FTL
|
||||||
case "${PROCESSOR}" in
|
case "${PROCESSOR}" in
|
||||||
"amd64") "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
|
"amd64") log_write "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
|
||||||
;;
|
;;
|
||||||
"armv6l") "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
|
"armv6l") log_write "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
|
||||||
;;
|
;;
|
||||||
"armv6") "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
|
"armv6") log_write "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
|
||||||
;;
|
;;
|
||||||
"armv7l") "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
|
"armv7l") log_write "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
|
||||||
;;
|
;;
|
||||||
"aarch64") "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
|
"aarch64") log_write "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
|
||||||
;;
|
;;
|
||||||
# Otherwise, show the processor type
|
# Otherwise, show the processor type
|
||||||
*) log_write "${INFO} ${PROCESSOR}";
|
*) log_write "${INFO} ${PROCESSOR}";
|
||||||
|
@ -493,13 +498,21 @@ parse_setup_vars() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse_locale() {
|
||||||
|
local pihole_locale
|
||||||
|
echo_current_diagnostic "Locale"
|
||||||
|
pihole_locale="$(locale)"
|
||||||
|
parse_file "${pihole_locale}"
|
||||||
|
}
|
||||||
|
|
||||||
does_ip_match_setup_vars() {
|
does_ip_match_setup_vars() {
|
||||||
# Check for IPv4 or 6
|
# Check for IPv4 or 6
|
||||||
local protocol="${1}"
|
local protocol="${1}"
|
||||||
# IP address to check for
|
# IP address to check for
|
||||||
local ip_address="${2}"
|
local ip_address="${2}"
|
||||||
# See what IP is in the setupVars.conf file
|
# See what IP is in the setupVars.conf file
|
||||||
local setup_vars_ip=$(< ${PIHOLE_SETUP_VARS_FILE} grep IPV${protocol}_ADDRESS | cut -d '=' -f2)
|
local setup_vars_ip
|
||||||
|
setup_vars_ip=$(< ${PIHOLE_SETUP_VARS_FILE} grep IPV"${protocol}"_ADDRESS | cut -d '=' -f2)
|
||||||
# If it's an IPv6 address
|
# If it's an IPv6 address
|
||||||
if [[ "${protocol}" == "6" ]]; then
|
if [[ "${protocol}" == "6" ]]; then
|
||||||
# Strip off the / (CIDR notation)
|
# Strip off the / (CIDR notation)
|
||||||
|
@ -530,10 +543,10 @@ detect_ip_addresses() {
|
||||||
# Use ip to show the addresses for the chosen protocol
|
# Use ip to show the addresses for the chosen protocol
|
||||||
# Store the values in an arry so they can be looped through
|
# Store the values in an arry so they can be looped through
|
||||||
# Get the lines that are in the file(s) and store them in an array for parsing later
|
# Get the lines that are in the file(s) and store them in an array for parsing later
|
||||||
declare -a ip_addr_list=( $(ip -${protocol} addr show dev ${PIHOLE_INTERFACE} | awk -F ' ' '{ for(i=1;i<=NF;i++) if ($i ~ '/^inet/') print $(i+1) }') )
|
mapfile -t ip_addr_list < <(ip -"${protocol}" addr show dev "${PIHOLE_INTERFACE}" | awk -F ' ' '{ for(i=1;i<=NF;i++) if ($i ~ '/^inet/') print $(i+1) }')
|
||||||
|
|
||||||
# If there is something in the IP address list,
|
# If there is something in the IP address list,
|
||||||
if [[ -n ${ip_addr_list} ]]; then
|
if [[ -n ${ip_addr_list[*]} ]]; then
|
||||||
# Local iterator
|
# Local iterator
|
||||||
local i
|
local i
|
||||||
# Display the protocol and interface
|
# Display the protocol and interface
|
||||||
|
@ -547,15 +560,15 @@ detect_ip_addresses() {
|
||||||
log_write ""
|
log_write ""
|
||||||
else
|
else
|
||||||
# If there are no IPs detected, explain that the protocol is not configured
|
# If there are no IPs detected, explain that the protocol is not configured
|
||||||
log_write "${CROSS} ${COL_RED}No IPv${protocol} address(es) found on the ${PIHOLE_INTERFACE}${COL_NC} interface.\n"
|
log_write "${CROSS} ${COL_RED}No IPv${protocol} address(es) found on the ${PIHOLE_INTERFACE}${COL_NC} interface.\\n"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
# If the protocol is v6
|
# If the protocol is v6
|
||||||
if [[ "${protocol}" == "6" ]]; then
|
if [[ "${protocol}" == "6" ]]; then
|
||||||
# let the user know that as long as there is one green address, things should be ok
|
# let the user know that as long as there is one green address, things should be ok
|
||||||
log_write " ^ Please note that you may have more than one IP address listed."
|
log_write " ^ Please note that you may have more than one IP address listed."
|
||||||
log_write " As long as one of them is green, and it matches what is in ${PIHOLE_SETUP_VARS_FILE}, there is no need for concern.\n"
|
log_write " As long as one of them is green, and it matches what is in ${PIHOLE_SETUP_VARS_FILE}, there is no need for concern.\\n"
|
||||||
log_write " The link to the FAQ is for an issue that sometimes occurs when the IPv6 address changes, which is why we check for it.\n"
|
log_write " The link to the FAQ is for an issue that sometimes occurs when the IPv6 address changes, which is why we check for it.\\n"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,7 +595,7 @@ ping_gateway() {
|
||||||
# Check if we are using IPv4 or IPv6
|
# Check if we are using IPv4 or IPv6
|
||||||
# Find the default gateway using IPv4 or IPv6
|
# Find the default gateway using IPv4 or IPv6
|
||||||
local gateway
|
local gateway
|
||||||
gateway="$(ip -${protocol} route | grep default | cut -d ' ' -f 3)"
|
gateway="$(ip -"${protocol}" route | grep default | cut -d ' ' -f 3)"
|
||||||
|
|
||||||
# If the gateway variable has a value (meaning a gateway was found),
|
# If the gateway variable has a value (meaning a gateway was found),
|
||||||
if [[ -n "${gateway}" ]]; then
|
if [[ -n "${gateway}" ]]; then
|
||||||
|
@ -592,9 +605,9 @@ ping_gateway() {
|
||||||
# Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only,
|
# Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only,
|
||||||
# on the pihole interface, and tail the last three lines of the output
|
# on the pihole interface, and tail the last three lines of the output
|
||||||
# If pinging the gateway is not successful,
|
# If pinging the gateway is not successful,
|
||||||
if ! ${cmd} -c 3 -W 2 -n ${gateway} -I ${PIHOLE_INTERFACE} >/dev/null; then
|
if ! ${cmd} -c 1 -W 2 -n "${gateway}" -I "${PIHOLE_INTERFACE}" >/dev/null; then
|
||||||
# let the user know
|
# let the user know
|
||||||
log_write "${CROSS} ${COL_RED}Gateway did not respond.${COL_NC} ($FAQ_GATEWAY)\n"
|
log_write "${CROSS} ${COL_RED}Gateway did not respond.${COL_NC} ($FAQ_GATEWAY)\\n"
|
||||||
# and return an error code
|
# and return an error code
|
||||||
return 1
|
return 1
|
||||||
# Otherwise,
|
# Otherwise,
|
||||||
|
@ -613,13 +626,13 @@ ping_internet() {
|
||||||
ping_ipv4_or_ipv6 "${protocol}"
|
ping_ipv4_or_ipv6 "${protocol}"
|
||||||
log_write "* Checking Internet connectivity via IPv${protocol}..."
|
log_write "* Checking Internet connectivity via IPv${protocol}..."
|
||||||
# Try to ping the address 3 times
|
# Try to ping the address 3 times
|
||||||
if ! ${cmd} -W 2 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} >/dev/null; then
|
if ! ${cmd} -c 1 -W 2 -n ${public_address} -I "${PIHOLE_INTERFACE}" >/dev/null; then
|
||||||
# if it's unsuccessful, show an error
|
# if it's unsuccessful, show an error
|
||||||
log_write "${CROSS} ${COL_RED}Cannot reach the Internet.${COL_NC}\n"
|
log_write "${CROSS} ${COL_RED}Cannot reach the Internet.${COL_NC}\\n"
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
# Otherwise, show success
|
# Otherwise, show success
|
||||||
log_write "${TICK} ${COL_GREEN}Query responded.${COL_NC}\n"
|
log_write "${TICK} ${COL_GREEN}Query responded.${COL_NC}\\n"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -652,15 +665,22 @@ check_required_ports() {
|
||||||
# Sort the addresses and remove duplicates
|
# Sort the addresses and remove duplicates
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
ports_in_use+=( "$line" )
|
ports_in_use+=( "$line" )
|
||||||
done < <( lsof -i -P -n | awk -F' ' '/LISTEN/ {print $9, $1}' | sort -n | uniq | cut -d':' -f2 )
|
done < <( lsof -iTCP -sTCP:LISTEN -P -n +c 10 )
|
||||||
|
|
||||||
# Now that we have the values stored,
|
# Now that we have the values stored,
|
||||||
for i in "${!ports_in_use[@]}"; do
|
for i in "${!ports_in_use[@]}"; do
|
||||||
# loop through them and assign some local variables
|
# loop through them and assign some local variables
|
||||||
local port_number
|
|
||||||
port_number="$(echo "${ports_in_use[$i]}" | awk '{print $1}')"
|
|
||||||
local service_name
|
local service_name
|
||||||
service_name=$(echo "${ports_in_use[$i]}" | awk '{print $2}')
|
service_name=$(echo "${ports_in_use[$i]}" | awk '{print $1}')
|
||||||
|
local protocol_type
|
||||||
|
protocol_type=$(echo "${ports_in_use[$i]}" | awk '{print $5}')
|
||||||
|
local port_number
|
||||||
|
port_number="$(echo "${ports_in_use[$i]}" | awk '{print $9}')"
|
||||||
|
|
||||||
|
# Skip the line if it's the titles of the columns the lsof command produces
|
||||||
|
if [[ "${service_name}" == COMMAND ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
# Use a case statement to determine if the right services are using the right ports
|
# Use a case statement to determine if the right services are using the right ports
|
||||||
case "${port_number}" in
|
case "${port_number}" in
|
||||||
53) compare_port_to_service_assigned "${resolver}"
|
53) compare_port_to_service_assigned "${resolver}"
|
||||||
|
@ -670,7 +690,7 @@ check_required_ports() {
|
||||||
4711) compare_port_to_service_assigned "${ftl}"
|
4711) compare_port_to_service_assigned "${ftl}"
|
||||||
;;
|
;;
|
||||||
# If it's not a default port that Pi-hole needs, just print it out for the user to see
|
# If it's not a default port that Pi-hole needs, just print it out for the user to see
|
||||||
*) log_write "[${port_number}] is in use by ${service_name}";
|
*) log_write "${port_number} ${service_name} (${protocol_type})";
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
@ -712,20 +732,20 @@ check_x_headers() {
|
||||||
# If the X-header found by curl matches what is should be,
|
# If the X-header found by curl matches what is should be,
|
||||||
if [[ $block_page == "$block_page_working" ]]; then
|
if [[ $block_page == "$block_page_working" ]]; then
|
||||||
# display a success message
|
# display a success message
|
||||||
log_write "$TICK ${COL_GREEN}${block_page}${COL_NC}"
|
log_write "$TICK Block page X-Header: ${COL_GREEN}${block_page}${COL_NC}"
|
||||||
else
|
else
|
||||||
# Otherwise, show an error
|
# Otherwise, show an error
|
||||||
log_write "$CROSS ${COL_RED}X-Header does not match or could not be retrieved.${COL_NC}"
|
log_write "$CROSS Block page X-Header: ${COL_RED}X-Header does not match or could not be retrieved.${COL_NC}"
|
||||||
log_write "${COL_RED}${full_curl_output_block_page}${COL_NC}"
|
log_write "${COL_RED}${full_curl_output_block_page}${COL_NC}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Same logic applies to the dashbord as above, if the X-Header matches what a working system shoud have,
|
# Same logic applies to the dashbord as above, if the X-Header matches what a working system shoud have,
|
||||||
if [[ $dashboard == "$dashboard_working" ]]; then
|
if [[ $dashboard == "$dashboard_working" ]]; then
|
||||||
# then we can show a success
|
# then we can show a success
|
||||||
log_write "$TICK ${COL_GREEN}${dashboard}${COL_NC}"
|
log_write "$TICK Web interface X-Header: ${COL_GREEN}${dashboard}${COL_NC}"
|
||||||
else
|
else
|
||||||
# Othewise, it's a failure since the X-Headers either don't exist or have been modified in some way
|
# Othewise, it's a failure since the X-Headers either don't exist or have been modified in some way
|
||||||
log_write "$CROSS ${COL_RED}X-Header does not match or could not be retrieved.${COL_NC}"
|
log_write "$CROSS Web interface X-Header: ${COL_RED}X-Header does not match or could not be retrieved.${COL_NC}"
|
||||||
log_write "${COL_RED}${full_curl_output_dashboard}${COL_NC}"
|
log_write "${COL_RED}${full_curl_output_dashboard}${COL_NC}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -751,14 +771,14 @@ dig_at() {
|
||||||
if [[ ${protocol} == "6" ]]; then
|
if [[ ${protocol} == "6" ]]; then
|
||||||
# Set the IPv6 variables and record type
|
# Set the IPv6 variables and record type
|
||||||
local local_address="::1"
|
local local_address="::1"
|
||||||
local pihole_address="${IPV6_ADDRESS%/*}"
|
local pihole_address="${IP}"
|
||||||
local remote_address="2001:4860:4860::8888"
|
local remote_address="2001:4860:4860::8888"
|
||||||
local record_type="AAAA"
|
local record_type="AAAA"
|
||||||
# Othwerwise, it should be 4
|
# Othwerwise, it should be 4
|
||||||
else
|
else
|
||||||
# so use the IPv4 values
|
# so use the IPv4 values
|
||||||
local local_address="127.0.0.1"
|
local local_address="127.0.0.1"
|
||||||
local pihole_address="${IPV4_ADDRESS%/*}"
|
local pihole_address="${IP}"
|
||||||
local remote_address="8.8.8.8"
|
local remote_address="8.8.8.8"
|
||||||
local record_type="A"
|
local record_type="A"
|
||||||
fi
|
fi
|
||||||
|
@ -766,7 +786,8 @@ dig_at() {
|
||||||
# Find a random blocked url that has not been whitelisted.
|
# Find a random blocked url that has not been whitelisted.
|
||||||
# This helps emulate queries to different domains that a user might query
|
# This helps emulate queries to different domains that a user might query
|
||||||
# It will also give extra assurance that Pi-hole is correctly resolving and blocking domains
|
# It will also give extra assurance that Pi-hole is correctly resolving and blocking domains
|
||||||
local random_url=$(shuf -n 1 "${PIHOLE_BLOCKLIST_FILE}" | awk -F ' ' '{ print $2 }')
|
local random_url
|
||||||
|
random_url=$(shuf -n 1 "${PIHOLE_BLOCKLIST_FILE}")
|
||||||
|
|
||||||
# First, do a dig on localhost to see if Pi-hole can use itself to block a domain
|
# First, do a dig on localhost to see if Pi-hole can use itself to block a domain
|
||||||
if local_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then
|
if local_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then
|
||||||
|
@ -783,7 +804,7 @@ dig_at() {
|
||||||
# The default timeouts and tries are reduced in case the DNS server isn't working, so the user isn't waiting for too long
|
# The default timeouts and tries are reduced in case the DNS server isn't working, so the user isn't waiting for too long
|
||||||
|
|
||||||
# If Pi-hole can dig itself from it's IP (not the loopback address)
|
# If Pi-hole can dig itself from it's IP (not the loopback address)
|
||||||
if pihole_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then
|
if pihole_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @"${pihole_address}" +short "${record_type}"); then
|
||||||
# show a success
|
# show a success
|
||||||
log_write "${TICK} ${random_url} ${COL_GREEN}is ${pihole_dig}${COL_NC} via ${COL_CYAN}Pi-hole${COL_NC} (${pihole_address})"
|
log_write "${TICK} ${random_url} ${COL_GREEN}is ${pihole_dig}${COL_NC} via ${COL_CYAN}Pi-hole${COL_NC} (${pihole_address})"
|
||||||
else
|
else
|
||||||
|
@ -812,10 +833,12 @@ process_status(){
|
||||||
# If systemd
|
# If systemd
|
||||||
if command -v systemctl &> /dev/null; then
|
if command -v systemctl &> /dev/null; then
|
||||||
# get its status via systemctl
|
# get its status via systemctl
|
||||||
local status_of_process=$(systemctl is-active "${i}")
|
local status_of_process
|
||||||
|
status_of_process=$(systemctl is-active "${i}")
|
||||||
else
|
else
|
||||||
# Otherwise, use the service command
|
# Otherwise, use the service command
|
||||||
local status_of_process=$(service "${i}" status | awk '/Active:/ {print $2}') &> /dev/null
|
local status_of_process
|
||||||
|
status_of_process=$(service "${i}" status | awk '/Active:/ {print $2}') &> /dev/null
|
||||||
fi
|
fi
|
||||||
# and print it out to the user
|
# and print it out to the user
|
||||||
if [[ "${status_of_process}" == "active" ]]; then
|
if [[ "${status_of_process}" == "active" ]]; then
|
||||||
|
@ -879,15 +902,20 @@ parse_file() {
|
||||||
# Put the current Internal Field Separator into another variable so it can be restored later
|
# Put the current Internal Field Separator into another variable so it can be restored later
|
||||||
OLD_IFS="$IFS"
|
OLD_IFS="$IFS"
|
||||||
# Get the lines that are in the file(s) and store them in an array for parsing later
|
# Get the lines that are in the file(s) and store them in an array for parsing later
|
||||||
|
local file_info
|
||||||
|
if [[ -f "$filename" ]]; then
|
||||||
|
#shellcheck disable=SC2016
|
||||||
IFS=$'\r\n' command eval 'file_info=( $(cat "${filename}") )'
|
IFS=$'\r\n' command eval 'file_info=( $(cat "${filename}") )'
|
||||||
|
else
|
||||||
|
read -a file_info <<< $filename
|
||||||
|
fi
|
||||||
# Set a named variable for better readability
|
# Set a named variable for better readability
|
||||||
local file_lines
|
local file_lines
|
||||||
# For each line in the file,
|
# For each line in the file,
|
||||||
for file_lines in "${file_info[@]}"; do
|
for file_lines in "${file_info[@]}"; do
|
||||||
if [[ ! -z "${file_lines}" ]]; then
|
if [[ ! -z "${file_lines}" ]]; then
|
||||||
# don't include the Web password hash
|
# don't include the Web password hash
|
||||||
[[ "${file_linesline}" =~ ^\#.*$ || ! "${file_lines}" || "${file_lines}" == "WEBPASSWORD="* ]] && continue
|
[[ "${file_lines}" =~ ^\#.*$ || ! "${file_lines}" || "${file_lines}" == "WEBPASSWORD="* ]] && continue
|
||||||
# otherwise, display the lines of the file
|
# otherwise, display the lines of the file
|
||||||
log_write " ${file_lines}"
|
log_write " ${file_lines}"
|
||||||
fi
|
fi
|
||||||
|
@ -931,7 +959,7 @@ list_files_in_dir() {
|
||||||
# Set the first argument passed to tihs function as a named variable for better readability
|
# Set the first argument passed to tihs function as a named variable for better readability
|
||||||
local dir_to_parse="${1}"
|
local dir_to_parse="${1}"
|
||||||
# Store the files found in an array
|
# Store the files found in an array
|
||||||
local files_found=( $(ls "${dir_to_parse}") )
|
mapfile -t files_found < <(ls "${dir_to_parse}")
|
||||||
# For each file in the array,
|
# For each file in the array,
|
||||||
for each_file in "${files_found[@]}"; do
|
for each_file in "${files_found[@]}"; do
|
||||||
if [[ -d "${dir_to_parse}/${each_file}" ]]; then
|
if [[ -d "${dir_to_parse}/${each_file}" ]]; then
|
||||||
|
@ -939,26 +967,26 @@ list_files_in_dir() {
|
||||||
:
|
:
|
||||||
elif [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_BLOCKLIST_FILE}" ]] || \
|
elif [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_BLOCKLIST_FILE}" ]] || \
|
||||||
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_DEBUG_LOG}" ]] || \
|
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_DEBUG_LOG}" ]] || \
|
||||||
[[ ${dir_to_parse}/${each_file} == ${PIHOLE_RAW_BLOCKLIST_FILES} ]] || \
|
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_RAW_BLOCKLIST_FILES}" ]] || \
|
||||||
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_INSTALL_LOG_FILE}" ]] || \
|
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_INSTALL_LOG_FILE}" ]] || \
|
||||||
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_SETUP_VARS_FILE}" ]] || \
|
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_SETUP_VARS_FILE}" ]] || \
|
||||||
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG}" ]] || \
|
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG}" ]] || \
|
||||||
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}" ]] || \
|
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}" ]] || \
|
||||||
[[ ${dir_to_parse}/${each_file} == ${PIHOLE_LOG_GZIPS} ]]; then
|
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG_GZIPS}" ]]; then
|
||||||
:
|
:
|
||||||
else
|
else
|
||||||
# Then, parse the file's content into an array so each line can be analyzed if need be
|
# Then, parse the file's content into an array so each line can be analyzed if need be
|
||||||
for i in "${!REQUIRED_FILES[@]}"; do
|
for i in "${!REQUIRED_FILES[@]}"; do
|
||||||
if [[ "${dir_to_parse}/${each_file}" == ${REQUIRED_FILES[$i]} ]]; then
|
if [[ "${dir_to_parse}/${each_file}" == "${REQUIRED_FILES[$i]}" ]]; then
|
||||||
# display the filename
|
# display the filename
|
||||||
log_write "\n${COL_GREEN}$(ls -ld ${dir_to_parse}/${each_file})${COL_NC}"
|
log_write "\\n${COL_GREEN}$(ls -ld "${dir_to_parse}"/"${each_file}")${COL_NC}"
|
||||||
# Check if the file we want to view has a limit (because sometimes we just need a little bit of info from the file, not the entire thing)
|
# Check if the file we want to view has a limit (because sometimes we just need a little bit of info from the file, not the entire thing)
|
||||||
case "${dir_to_parse}/${each_file}" in
|
case "${dir_to_parse}/${each_file}" in
|
||||||
# If it's Web server error log, just give the first 25 lines
|
# If it's Web server error log, just give the first 25 lines
|
||||||
"${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}") make_array_from_file "${dir_to_parse}/${each_file}" 25
|
"${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}") make_array_from_file "${dir_to_parse}/${each_file}" 25
|
||||||
;;
|
;;
|
||||||
# Same for the FTL log
|
# Same for the FTL log
|
||||||
"${PIHOLE_FTL_LOG}") make_array_from_file "${dir_to_parse}/${each_file}" 25
|
"${PIHOLE_FTL_LOG}") head_tail_log "${dir_to_parse}/${each_file}" 35
|
||||||
;;
|
;;
|
||||||
# parse the file into an array in case we ever need to analyze it line-by-line
|
# parse the file into an array in case we ever need to analyze it line-by-line
|
||||||
*) make_array_from_file "${dir_to_parse}/${each_file}";
|
*) make_array_from_file "${dir_to_parse}/${each_file}";
|
||||||
|
@ -991,6 +1019,34 @@ show_content_of_pihole_files() {
|
||||||
show_content_of_files_in_dir "${LOG_DIRECTORY}"
|
show_content_of_files_in_dir "${LOG_DIRECTORY}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
head_tail_log() {
|
||||||
|
# The file being processed
|
||||||
|
local filename="${1}"
|
||||||
|
# The number of lines to use for head and tail
|
||||||
|
local qty="${2}"
|
||||||
|
local head_line
|
||||||
|
local tail_line
|
||||||
|
# Put the current Internal Field Separator into another variable so it can be restored later
|
||||||
|
OLD_IFS="$IFS"
|
||||||
|
# Get the lines that are in the file(s) and store them in an array for parsing later
|
||||||
|
IFS=$'\r\n'
|
||||||
|
local log_head=()
|
||||||
|
mapfile -t log_head < <(head -n "${qty}" "${filename}")
|
||||||
|
log_write " ${COL_CYAN}-----head of $(basename "${filename}")------${COL_NC}"
|
||||||
|
for head_line in "${log_head[@]}"; do
|
||||||
|
log_write " ${head_line}"
|
||||||
|
done
|
||||||
|
log_write ""
|
||||||
|
local log_tail=()
|
||||||
|
mapfile -t log_tail < <(tail -n "${qty}" "${filename}")
|
||||||
|
log_write " ${COL_CYAN}-----tail of $(basename "${filename}")------${COL_NC}"
|
||||||
|
for tail_line in "${log_tail[@]}"; do
|
||||||
|
log_write " ${tail_line}"
|
||||||
|
done
|
||||||
|
# Set the IFS back to what it was
|
||||||
|
IFS="$OLD_IFS"
|
||||||
|
}
|
||||||
|
|
||||||
analyze_gravity_list() {
|
analyze_gravity_list() {
|
||||||
echo_current_diagnostic "Gravity list"
|
echo_current_diagnostic "Gravity list"
|
||||||
local head_line
|
local head_line
|
||||||
|
@ -999,17 +1055,18 @@ analyze_gravity_list() {
|
||||||
OLD_IFS="$IFS"
|
OLD_IFS="$IFS"
|
||||||
# Get the lines that are in the file(s) and store them in an array for parsing later
|
# Get the lines that are in the file(s) and store them in an array for parsing later
|
||||||
IFS=$'\r\n'
|
IFS=$'\r\n'
|
||||||
local gravity_permissions=$(ls -ld "${PIHOLE_BLOCKLIST_FILE}")
|
local gravity_permissions
|
||||||
|
gravity_permissions=$(ls -ld "${PIHOLE_BLOCKLIST_FILE}")
|
||||||
log_write "${COL_GREEN}${gravity_permissions}${COL_NC}"
|
log_write "${COL_GREEN}${gravity_permissions}${COL_NC}"
|
||||||
local gravity_head=()
|
local gravity_head=()
|
||||||
gravity_head=( $(head -n 4 ${PIHOLE_BLOCKLIST_FILE}) )
|
mapfile -t gravity_head < <(head -n 4 ${PIHOLE_BLOCKLIST_FILE})
|
||||||
log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_BLOCKLIST_FILE})------${COL_NC}"
|
log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_BLOCKLIST_FILE})------${COL_NC}"
|
||||||
for head_line in "${gravity_head[@]}"; do
|
for head_line in "${gravity_head[@]}"; do
|
||||||
log_write " ${head_line}"
|
log_write " ${head_line}"
|
||||||
done
|
done
|
||||||
log_write ""
|
log_write ""
|
||||||
local gravity_tail=()
|
local gravity_tail=()
|
||||||
gravity_tail=( $(tail -n 4 ${PIHOLE_BLOCKLIST_FILE}) )
|
mapfile -t gravity_tail < <(tail -n 4 ${PIHOLE_BLOCKLIST_FILE})
|
||||||
log_write " ${COL_CYAN}-----tail of $(basename ${PIHOLE_BLOCKLIST_FILE})------${COL_NC}"
|
log_write " ${COL_CYAN}-----tail of $(basename ${PIHOLE_BLOCKLIST_FILE})------${COL_NC}"
|
||||||
for tail_line in "${gravity_tail[@]}"; do
|
for tail_line in "${gravity_tail[@]}"; do
|
||||||
log_write " ${tail_line}"
|
log_write " ${tail_line}"
|
||||||
|
@ -1025,10 +1082,11 @@ analyze_pihole_log() {
|
||||||
OLD_IFS="$IFS"
|
OLD_IFS="$IFS"
|
||||||
# Get the lines that are in the file(s) and store them in an array for parsing later
|
# Get the lines that are in the file(s) and store them in an array for parsing later
|
||||||
IFS=$'\r\n'
|
IFS=$'\r\n'
|
||||||
local pihole_log_permissions=$(ls -ld "${PIHOLE_LOG}")
|
local pihole_log_permissions
|
||||||
|
pihole_log_permissions=$(ls -ld "${PIHOLE_LOG}")
|
||||||
log_write "${COL_GREEN}${pihole_log_permissions}${COL_NC}"
|
log_write "${COL_GREEN}${pihole_log_permissions}${COL_NC}"
|
||||||
local pihole_log_head=()
|
local pihole_log_head=()
|
||||||
pihole_log_head=( $(head -n 20 ${PIHOLE_LOG}) )
|
mapfile -t pihole_log_head < <(head -n 20 ${PIHOLE_LOG})
|
||||||
log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_LOG})------${COL_NC}"
|
log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_LOG})------${COL_NC}"
|
||||||
local error_to_check_for
|
local error_to_check_for
|
||||||
local line_to_obfuscate
|
local line_to_obfuscate
|
||||||
|
@ -1038,10 +1096,10 @@ analyze_pihole_log() {
|
||||||
# that the DNS server is attempting to read. Since it's not formatted
|
# that the DNS server is attempting to read. Since it's not formatted
|
||||||
# correctly, there will be an entry for "bad address at line n"
|
# correctly, there will be an entry for "bad address at line n"
|
||||||
# So we can check for that here and highlight it in red so the user can see it easily
|
# So we can check for that here and highlight it in red so the user can see it easily
|
||||||
error_to_check_for=$(echo ${head_line} | grep 'bad address at')
|
error_to_check_for=$(echo "${head_line}" | grep 'bad address at')
|
||||||
# Some users may not want to have the domains they visit sent to us
|
# Some users may not want to have the domains they visit sent to us
|
||||||
# To that end, we check for lines in the log that would contain a domain name
|
# To that end, we check for lines in the log that would contain a domain name
|
||||||
line_to_obfuscate=$(echo ${head_line} | grep ': query\|: forwarded\|: reply')
|
line_to_obfuscate=$(echo "${head_line}" | grep ': query\|: forwarded\|: reply')
|
||||||
# If the variable contains a value, it found an error in the log
|
# If the variable contains a value, it found an error in the log
|
||||||
if [[ -n ${error_to_check_for} ]]; then
|
if [[ -n ${error_to_check_for} ]]; then
|
||||||
# So we can print it in red to make it visible to the user
|
# So we can print it in red to make it visible to the user
|
||||||
|
@ -1056,7 +1114,7 @@ analyze_pihole_log() {
|
||||||
if [[ -n ${line_to_obfuscate} ]]; then
|
if [[ -n ${line_to_obfuscate} ]]; then
|
||||||
# If there are, we need to use awk to replace only the domain name (the 6th field in the log)
|
# If there are, we need to use awk to replace only the domain name (the 6th field in the log)
|
||||||
# so we substitue the domain for the placeholder value
|
# so we substitue the domain for the placeholder value
|
||||||
obfuscated_line=$(echo ${line_to_obfuscate} | awk -v placeholder="${OBFUSCATED_PLACEHOLDER}" '{sub($6,placeholder); print $0}')
|
obfuscated_line=$(echo "${line_to_obfuscate}" | awk -v placeholder="${OBFUSCATED_PLACEHOLDER}" '{sub($6,placeholder); print $0}')
|
||||||
log_write " ${obfuscated_line}"
|
log_write " ${obfuscated_line}"
|
||||||
else
|
else
|
||||||
log_write " ${head_line}"
|
log_write " ${head_line}"
|
||||||
|
@ -1097,7 +1155,7 @@ upload_to_tricorder() {
|
||||||
log_write ""
|
log_write ""
|
||||||
log_write "${COL_PURPLE}********************************************${COL_NC}"
|
log_write "${COL_PURPLE}********************************************${COL_NC}"
|
||||||
log_write "${COL_PURPLE}********************************************${COL_NC}"
|
log_write "${COL_PURPLE}********************************************${COL_NC}"
|
||||||
log_write "${TICK} ${COL_GREEN}** FINISHED DEBUGGING! **${COL_NC}\n"
|
log_write "${TICK} ${COL_GREEN}** FINISHED DEBUGGING! **${COL_NC}\\n"
|
||||||
|
|
||||||
# Provide information on what they should do with their token
|
# Provide information on what they should do with their token
|
||||||
log_write " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only."
|
log_write " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only."
|
||||||
|
@ -1144,7 +1202,7 @@ upload_to_tricorder() {
|
||||||
log_write " * Please try again or contact the Pi-hole team for assistance."
|
log_write " * Please try again or contact the Pi-hole team for assistance."
|
||||||
fi
|
fi
|
||||||
# Finally, show where the log file is no matter the outcome of the function so users can look at it
|
# Finally, show where the log file is no matter the outcome of the function so users can look at it
|
||||||
log_write " * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG_SANITIZED}${COL_NC}\n"
|
log_write " * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG_SANITIZED}${COL_NC}\\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run through all the functions we made
|
# Run through all the functions we made
|
||||||
|
@ -1165,6 +1223,7 @@ parse_setup_vars
|
||||||
check_x_headers
|
check_x_headers
|
||||||
analyze_gravity_list
|
analyze_gravity_list
|
||||||
show_content_of_pihole_files
|
show_content_of_pihole_files
|
||||||
|
parse_locale
|
||||||
analyze_pihole_log
|
analyze_pihole_log
|
||||||
copy_to_debug_log
|
copy_to_debug_log
|
||||||
upload_to_tricorder
|
upload_to_tricorder
|
||||||
|
|
|
@ -16,7 +16,10 @@ 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"
|
||||||
|
|
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
|
|
@ -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,9 +31,12 @@ 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
|
||||||
|
directory="${1}"
|
||||||
curdir=$PWD
|
curdir=$PWD
|
||||||
cd "${directory}" || return
|
cd "${directory}" || return
|
||||||
|
|
||||||
|
@ -51,14 +57,14 @@ GitCheckUpdateAvail() {
|
||||||
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
|
||||||
|
@ -77,31 +83,23 @@ GitCheckUpdateAvail() {
|
||||||
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 web_version_current
|
|
||||||
local basicError="\\n ${COL_LIGHT_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
|
local basicError="\\n ${COL_LIGHT_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
|
||||||
|
local core_update
|
||||||
|
local web_update
|
||||||
|
local FTL_update
|
||||||
|
|
||||||
|
core_update=false
|
||||||
|
web_update=false
|
||||||
|
FTL_update=false
|
||||||
|
|
||||||
# shellcheck disable=1090,2154
|
# shellcheck disable=1090,2154
|
||||||
source "${setupVars}"
|
source "${setupVars}"
|
||||||
|
|
||||||
# This is unlikely
|
# This is unlikely
|
||||||
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||||
echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!
|
echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!"
|
||||||
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
|
||||||
|
|
||||||
|
@ -115,28 +113,10 @@ main() {
|
||||||
echo -e " ${INFO} Pi-hole Core:\\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
|
||||||
|
|
||||||
if FTLcheckUpdate ; then
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
FTL_update=true
|
|
||||||
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
|
|
||||||
else
|
|
||||||
FTL_update=false
|
|
||||||
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Logic: Don't update FTL when there is a core update available
|
|
||||||
# since the core update will run the installer which will itself
|
|
||||||
# re-install (i.e. update) FTL
|
|
||||||
if ${FTL_update} && ! ${core_update}; then
|
|
||||||
echo ""
|
|
||||||
echo -e " ${INFO} FTL out of date"
|
|
||||||
FTLdetect
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${INSTALL_WEB}" == true ]]; then
|
|
||||||
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
|
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
|
||||||
echo -e "\\n ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!
|
echo -e "\\n ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!"
|
||||||
Please re-run install script from https://pi-hole.net${COL_NC}"
|
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -147,82 +127,65 @@ main() {
|
||||||
web_update=false
|
web_update=false
|
||||||
echo -e " ${INFO} Web Interface:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
echo -e " ${INFO} Web Interface:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Logic
|
if FTLcheckUpdate > /dev/null; then
|
||||||
# If Core up to date AND web up to date:
|
FTL_update=true
|
||||||
# Do nothing
|
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
|
||||||
# If Core up to date AND web NOT up to date:
|
else
|
||||||
# Pull web repo
|
case $? in
|
||||||
# If Core NOT up to date AND web up to date:
|
1)
|
||||||
# pull pihole repo, run install --unattended -- reconfigure
|
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
||||||
# if Core NOT up to date AND web NOT up to date:
|
;;
|
||||||
# pull pihole repo run install --unattended
|
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} && ! ${web_update} ; then
|
if [[ "${core_update}" == false && "${web_update}" == false && "${FTL_update}" == false ]]; then
|
||||||
if ! ${FTL_update} ; then
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${TICK} Everything is up to date!"
|
echo -e " ${TICK} Everything is up to date!"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
elif ! ${core_update} && ${web_update} ; then
|
|
||||||
echo ""
|
|
||||||
echo -e " ${INFO} Pi-hole Web Admin files out of date"
|
|
||||||
getGitFiles "${ADMIN_INTERFACE_DIR}" "${ADMIN_INTERFACE_GIT_URL}"
|
|
||||||
elif ${core_update} && ! ${web_update} ; then
|
|
||||||
echo ""
|
|
||||||
echo -e " ${INFO} Pi-hole core files out of date"
|
|
||||||
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
|
|
||||||
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
|
|
||||||
echo -e "${basicError}" && exit 1
|
|
||||||
elif ${core_update} && ${web_update} ; then
|
|
||||||
echo ""
|
|
||||||
echo -e " ${INFO} Updating Pi-hole core and web admin files"
|
|
||||||
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
|
|
||||||
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --unattended || \
|
|
||||||
echo -e "${basicError}" && exit 1
|
|
||||||
else
|
|
||||||
echo -e " ${COL_LIGHT_RED}Update script has malfunctioned, please contact Pi-hole Support${COL_NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else # Web Admin not installed, so only verify if core is up to date
|
|
||||||
if ! ${core_update}; then
|
|
||||||
if ! ${FTL_update} ; then
|
|
||||||
echo ""
|
|
||||||
echo -e " ${INFO} Everything is up to date!"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo ""
|
|
||||||
echo -e " ${INFO} Pi-hole Core files out of date"
|
|
||||||
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
|
|
||||||
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
|
|
||||||
echo -e "${basicError}" && exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${web_update}" == true ]]; then
|
if [[ "${CHECK_ONLY}" == 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
|
fi
|
||||||
|
|
||||||
if [[ "${core_update}" == true ]]; then
|
if [[ "${core_update}" == true ]]; then
|
||||||
pihole_version_current="$(/usr/local/bin/pihole version --pihole --current)"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${INFO} Pi-hole version is now at ${pihole_version_current/* v/v}
|
echo -e " ${INFO} Pi-hole core files out of date, updating local repo."
|
||||||
${INFO} If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'"
|
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
|
fi
|
||||||
|
|
||||||
if [[ "${FTL_update}" == true ]]; then
|
if [[ "${FTL_update}" == true ]]; then
|
||||||
FTL_version_current="$(/usr/bin/pihole-FTL tag)"
|
echo ""
|
||||||
echo -e "\\n ${INFO} FTL version is now at ${FTL_version_current/* v/v}"
|
echo -e " ${INFO} FTL out of date, it will be updated by the installer."
|
||||||
start_service pihole-FTL
|
|
||||||
enable_service pihole-FTL
|
|
||||||
fi
|
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
|
||||||
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if [[ "$1" == "--check-only" ]]; then
|
||||||
|
CHECK_ONLY=true
|
||||||
|
fi
|
||||||
|
|
||||||
main
|
main
|
||||||
|
|
|
@ -32,9 +32,9 @@ function get_local_branch() {
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
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"
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +53,19 @@ change_setting() {
|
||||||
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}"
|
||||||
|
@ -135,6 +149,14 @@ ProcessDNSSettings() {
|
||||||
let COUNTER=COUNTER+1
|
let COUNTER=COUNTER+1
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# The option LOCAL_DNS_PORT is deprecated
|
||||||
|
# We apply it once more, and then convert it into the current format
|
||||||
|
if [ ! -z "${LOCAL_DNS_PORT}" ]; then
|
||||||
|
add_dnsmasq_setting "server" "127.0.0.1#${LOCAL_DNS_PORT}"
|
||||||
|
add_setting "PIHOLE_DNS_${COUNTER}" "127.0.0.1#${LOCAL_DNS_PORT}"
|
||||||
|
delete_setting "LOCAL_DNS_PORT"
|
||||||
|
fi
|
||||||
|
|
||||||
delete_dnsmasq_setting "domain-needed"
|
delete_dnsmasq_setting "domain-needed"
|
||||||
|
|
||||||
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
|
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
|
||||||
|
@ -182,11 +204,11 @@ trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC68345710423
|
||||||
|
|
||||||
add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
|
add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${CONDITIONAL_FORWARDING}" == true ]]; then
|
if [[ "${CONDITIONAL_FORWARDING}" == true ]]; then
|
||||||
add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_DOMAIN}/${CONDITIONAL_FORWARDING_IP}"
|
add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_DOMAIN}/${CONDITIONAL_FORWARDING_IP}"
|
||||||
add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_REVERSE}/${CONDITIONAL_FORWARDING_IP}"
|
add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_REVERSE}/${CONDITIONAL_FORWARDING_IP}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetDNSServers() {
|
SetDNSServers() {
|
||||||
|
@ -215,6 +237,7 @@ SetDNSServers() {
|
||||||
else
|
else
|
||||||
change_setting "DNSSEC" "false"
|
change_setting "DNSSEC" "false"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${args[6]}" == "conditional_forwarding" ]]; then
|
if [[ "${args[6]}" == "conditional_forwarding" ]]; then
|
||||||
change_setting "CONDITIONAL_FORWARDING" "true"
|
change_setting "CONDITIONAL_FORWARDING" "true"
|
||||||
change_setting "CONDITIONAL_FORWARDING_IP" "${args[7]}"
|
change_setting "CONDITIONAL_FORWARDING_IP" "${args[7]}"
|
||||||
|
@ -361,7 +384,9 @@ CustomizeAdLists() {
|
||||||
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
|
||||||
|
if [[ $(grep -c "^${args[3]}$" "${list}") -eq 0 ]] ; then
|
||||||
echo "${args[3]}" >> ${list}
|
echo "${args[3]}" >> ${list}
|
||||||
|
fi
|
||||||
elif [[ "${args[2]}" == "del" ]]; then
|
elif [[ "${args[2]}" == "del" ]]; then
|
||||||
var=$(echo "${args[3]}" | sed 's/\//\\\//g')
|
var=$(echo "${args[3]}" | sed 's/\//\\\//g')
|
||||||
sed -i "/${var}/Id" "${list}"
|
sed -i "/${var}/Id" "${list}"
|
||||||
|
@ -505,6 +530,13 @@ 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=("$@")
|
||||||
|
|
||||||
|
@ -534,6 +566,7 @@ main() {
|
||||||
"-t" | "teleporter" ) Teleporter;;
|
"-t" | "teleporter" ) Teleporter;;
|
||||||
"adlist" ) CustomizeAdLists;;
|
"adlist" ) CustomizeAdLists;;
|
||||||
"audit" ) audit;;
|
"audit" ) audit;;
|
||||||
|
"-l" | "privacylevel" ) SetPrivacyLevel;;
|
||||||
* ) helpFunc;;
|
* ) helpFunc;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
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]}"
|
||||||
|
|
||||||
|
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}) )
|
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
|
@ -14,8 +14,8 @@ 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
|
||||||
|
|
||||||
|
@ -46,34 +46,24 @@ 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[@]}")
|
||||||
|
if [[ "${INSTALL_WEB_SERVER}" == true ]]; then
|
||||||
# Install the Web dependencies
|
# Install the Web dependencies
|
||||||
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}" "${PIHOLE_WEB_DEPS[@]}")
|
DEPS+=("${PIHOLE_WEB_DEPS[@]}")
|
||||||
# Otherwise,
|
|
||||||
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
|
|
||||||
PKG_REMOVE="${PKG_MANAGER} remove -y"
|
|
||||||
package_check() {
|
|
||||||
rpm -qa | grep ^$1- > /dev/null
|
|
||||||
}
|
|
||||||
package_cleanup() {
|
|
||||||
${SUDO} ${PKG_MANAGER} -y autoremove
|
|
||||||
}
|
|
||||||
elif [ -x "$(command -v apt-get)" ]; then
|
|
||||||
# Debian Family
|
# Debian Family
|
||||||
PKG_REMOVE="${PKG_MANAGER} -y remove --purge"
|
PKG_REMOVE="${PKG_MANAGER} -y remove --purge"
|
||||||
package_check() {
|
package_check() {
|
||||||
dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -c "ok installed"
|
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
|
||||||
${SUDO} ${PKG_MANAGER} -y autoclean
|
PKG_REMOVE="${PKG_MANAGER} remove -y"
|
||||||
|
package_check() {
|
||||||
|
rpm -qa | grep "^$1-" > /dev/null
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
echo -e " ${CROSS} OS distribution not supported"
|
echo -e " ${CROSS} OS distribution not supported"
|
||||||
|
@ -84,14 +74,13 @@ 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;;
|
||||||
|
@ -103,14 +92,9 @@ removeAndPurge() {
|
||||||
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
|
|
||||||
echo -ne " ${INFO} Removing & cleaning remaining dependencies..."
|
|
||||||
package_cleanup &> /dev/null
|
|
||||||
echo -e "${OVER} ${TICK} Removed & cleaned up remaining dependencies"
|
|
||||||
|
|
||||||
# Call removeNoPurge to remove Pi-hole specific files
|
# Call removeNoPurge to remove Pi-hole specific files
|
||||||
removeNoPurge
|
removeNoPurge
|
||||||
}
|
}
|
||||||
|
@ -168,32 +152,42 @@ removeNoPurge() {
|
||||||
${SUDO} rm -f /etc/sudoers.d/pihole &> /dev/null
|
${SUDO} rm -f /etc/sudoers.d/pihole &> /dev/null
|
||||||
echo -e " ${TICK} Removed config files"
|
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
|
# Remove FTL
|
||||||
if command -v pihole-FTL &> /dev/null; then
|
if command -v pihole-FTL &> /dev/null; then
|
||||||
echo -ne " ${INFO} Removing pihole-FTL..."
|
echo -ne " ${INFO} Removing pihole-FTL..."
|
||||||
|
|
||||||
if [[ -x "$(command -v systemctl)" ]]; then
|
if [[ -x "$(command -v systemctl)" ]]; then
|
||||||
systemctl stop pihole-FTL
|
systemctl stop pihole-FTL
|
||||||
else
|
else
|
||||||
service pihole-FTL stop
|
service pihole-FTL stop
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${SUDO} rm -f /etc/init.d/pihole-FTL
|
${SUDO} rm -f /etc/init.d/pihole-FTL
|
||||||
${SUDO} rm -f /usr/bin/pihole-FTL
|
${SUDO} rm -f /usr/bin/pihole-FTL
|
||||||
echo -e "${OVER} ${TICK} Removed pihole-FTL"
|
echo -e "${OVER} ${TICK} Removed pihole-FTL"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# If the pihole manpage exists, then delete and rebuild man-db
|
||||||
|
if [[ -f /usr/local/share/man/man8/pihole.8 ]]; then
|
||||||
|
${SUDO} rm -f /usr/local/share/man/man8/pihole.8 /usr/local/share/man/man8/pihole-FTL.8 /usr/local/share/man/man5/pihole-FTL.conf.5
|
||||||
|
${SUDO} mandb -q &>/dev/null
|
||||||
|
echo -e " ${TICK} Removed pihole man page"
|
||||||
|
fi
|
||||||
|
|
||||||
# If the pihole user exists, then remove
|
# If the pihole user exists, then remove
|
||||||
if id "pihole" &> /dev/null; then
|
if id "pihole" &> /dev/null; then
|
||||||
${SUDO} userdel -r pihole 2> /dev/null
|
if ${SUDO} userdel -r pihole 2> /dev/null; then
|
||||||
if [[ "$?" -eq 0 ]]; then
|
|
||||||
echo -e " ${TICK} Removed 'pihole' user"
|
echo -e " ${TICK} Removed 'pihole' user"
|
||||||
else
|
else
|
||||||
echo -e " ${CROSS} Unable to remove 'pihole' user"
|
echo -e " ${CROSS} Unable to remove 'pihole' user"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "\n We're sorry to see you go, but thanks for checking out Pi-hole!
|
echo -e "\\n We're sorry to see you go, but thanks for checking out Pi-hole!
|
||||||
If you need help, reach out to us on Github, Discourse, Reddit or Twitter
|
If you need help, reach out to us on Github, Discourse, Reddit or Twitter
|
||||||
Reinstall at any time: ${COL_WHITE}curl -sSL https://install.pi-hole.net | bash${COL_NC}
|
Reinstall at any time: ${COL_WHITE}curl -sSL https://install.pi-hole.net | bash${COL_NC}
|
||||||
|
|
||||||
|
|
121
gravity.sh
121
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"
|
||||||
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
echo -ne " ${INFO} ${str}..."
|
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"
|
||||||
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
echo -ne " ${INFO} ${str}..."
|
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"
|
||||||
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
echo -ne " ${INFO} ${str}..."
|
echo -ne " ${INFO} ${str}..."
|
||||||
sort -u "${piholeDir}/${parsedMatter}" > "${piholeDir}/${preEventHorizon}"
|
fi
|
||||||
echo -e "${OVER} ${TICK} ${str}"
|
|
||||||
|
|
||||||
|
sort -u "${piholeDir}/${parsedMatter}" > "${piholeDir}/${preEventHorizon}"
|
||||||
|
|
||||||
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
|
echo -e "${OVER} ${TICK} ${str}"
|
||||||
# Format $preEventHorizon line total as currency
|
# Format $preEventHorizon line total as currency
|
||||||
num=$(printf "%'.0f" "$(wc -l < "${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}"
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,10 +519,10 @@ gravity_ParseBlacklistDomains() {
|
||||||
: > "${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
|
||||||
|
if [[ "${haveSourceUrls}" == true ]]; then
|
||||||
gravity_SetDownloadOptions
|
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