Merge branch 'development' of https://github.com/pi-hole/pi-hole into InstallFixes_UnitTests

pull/894/head
diginc 8 years ago
commit b4524839bb

@ -0,0 +1,3 @@
engines:
shellcheck:
enabled: true

38
.gitattributes vendored

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

@ -1,23 +1,21 @@
_This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._ **In raising this issue, I confirm the following (please check boxes, eg [X]) Failure to fill the template will close your issue:**
**In raising this issue, I confirm the following (please check boxes, eg [X]):**
- [ ] I have read and understood the [contributors guide](https://github.com/pi-hole/pi-hole/blob/master/CONTRIBUTING.md). - [] I have read and understood the [contributors guide](https://github.com/pi-hole/pi-hole/blob/master/CONTRIBUTING.md).
- [ ] The issue I am reporting can be *replicated* - [] The issue I am reporting can be *replicated*
- [ ] The issue I'm reporting isn't a duplicate (see [FAQs](https://github.com/pi-hole/pi-hole/wiki/FAQs), [closed issues](https://github.com/pi-hole/pi-hole/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), and [open issues](https://github.com/pi-hole/pi-hole/issues)). - [] The issue I'm reporting isn't a duplicate (see [FAQs](https://github.com/pi-hole/pi-hole/wiki/FAQs), [closed issues](https://github.com/pi-hole/pi-hole/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), and [open issues](https://github.com/pi-hole/pi-hole/issues)).
**How familiar are you with the codebase?:** **How familiar are you with the codebase?:**
- [ ] 1 (very unfamiliar) - [] 1 (very unfamiliar)
- [ ] 2 - [] 2
- [ ] 3 - [] 3
- [ ] 4 - [] 4
- [ ] 5 - [] 5
- [ ] 6 - [] 6
- [ ] 7 - [] 7
- [ ] 8 - [] 8
- [ ] 9 - [] 9
- [ ] 10 (very familiar) - [] 10 (very familiar)
--- ---
**[FEATURE REQUEST | QUESTION | OTHER]:** **[FEATURE REQUEST | QUESTION | OTHER]:**
@ -40,3 +38,5 @@ _{replace this section with your content or delete if not a FEATURE REQUEST/QUES
**(Optional) Debug Log generated by `pihole -d`:** **(Optional) Debug Log generated by `pihole -d`:**
`http://termbin.com/<something>` `http://termbin.com/<something>`
_This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._

@ -1,25 +1,26 @@
_This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._ **By submitting this pull request, I confirm the following (please check boxes, eg [X])Failure to fill the template will close your PR:**
**By submitting this pull request, I confirm the following (please check boxes, eg [X]):**
- [ ] I have read and understood the [contributors guide](https://github.com/pi-hole/pi-hole/blob/master/CONTRIBUTING.md). - [] I have read and understood the [contributors guide](https://github.com/pi-hole/pi-hole/blob/master/CONTRIBUTING.md).
- [ ] I have checked that [another pull request](https://github.com/pi-hole/pi-hole/pulls) for this purpose does not exist. - [] I have checked that [another pull request](https://github.com/pi-hole/pi-hole/pulls) for this purpose does not exist.
- [ ] I have considered, and confirmed that this submission will be valuable to others. - [] I have considered, and confirmed that this submission will be valuable to others.
- [ ] I accept that this submission may not be used, and the pull request closed at the will of the maintainer. - [] I accept that this submission may not be used, and the pull request closed at the will of the maintainer.
- [ ] I give this submission freely, and claim no ownership to its content. - [] I give this submission freely, and claim no ownership to its content.
**How familiar are you with the codebase?:** **How familiar are you with the codebase?:**
- [ ] 1 (very unfamiliar) - [] 1 (very unfamiliar)
- [ ] 2 - [] 2
- [ ] 3 - [] 3
- [ ] 4 - [] 4
- [ ] 5 - [] 5
- [ ] 6 - [] 6
- [ ] 7 - [] 7
- [ ] 8 - [] 8
- [ ] 9 - [] 9
- [ ] 10 (very familiar) - [] 10 (very familiar)
--- ---
_{replace this line with your pull request content}_ _{replace this line with your pull request content}_
_This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._

@ -1,19 +1,38 @@
approve_by_comment: true version: 2
approve_regex: '^(Approved|:shipit:|:\+1:|Engage)'
reject_regex: '^(Rejected|:-1:|Borg)'
reset_on_push: true
author_approval: required
reviewers:
members:
- brantje
- dschaper
- jacobsalmela
- Mcat12
- PromoFaux
name: pullapprove
required: 3
always_pending: always_pending:
title_regex: '(WIP|wip)' title_regex: '(WIP|wip)'
labels: labels:
- wip - wip
explanation: 'This PR is a work in progress...' explanation: 'This PR is a work in progress...'
group_defaults:
reset_on_push:
enabled: true
reject_value: -2
approve_regex: '^(Approved|:shipit:|:\+1:|Engage)'
reject_regex: '^(Rejected|:-1:|Borg)'
author_approval:
auto: true
groups:
development:
approve_by_comment:
enabled: true
conditions:
branches:
- development
required: 2
teams:
- gravity
master:
approve_by_comment:
enabled: true
conditions:
branches:
- master
required: -1
teams:
- admin

@ -1,4 +1,4 @@
[![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=3011939)](https://www.bountysource.com/trackers/3011939-pi-hole-pi-hole?utm_source=3011939&utm_medium=shield&utm_campaign=TRACKER_BADGE) [![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=3011939)](https://www.bountysource.com/trackers/3011939-pi-hole-pi-hole?utm_source=3011939&utm_medium=shield&utm_campaign=TRACKER_BADGE) [![Code Climate](https://codeclimate.com/github/pi-hole/pi-hole/badges/gpa.svg)](https://codeclimate.com/github/pi-hole/pi-hole)
# Automated Install # Automated Install
@ -8,17 +8,15 @@ Works on most Debian and CentOS/RHEL based distributions!
1. Install Raspbian 1. Install Raspbian
2. Run the command below (downloads [this script](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) in case you want to read over it first!) 2. Run the command below (downloads [this script](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) in case you want to read over it first!)
## `curl -L https://install.pi-hole.net | bash` ### `curl -sSL https://install.pi-hole.net | bash`
### Alternative Semi-Automated install ### Alternative Semi-Automated install
```bash ```bash
wget -O basic-install.sh https://install.pi-hole.net wget -O basic-install.sh https://install.pi-hole.net
chmod +x basic-install.sh cat basic-install.sh | bash
./basic-install.sh
``` ```
If you wish to read over the script before running it, then after the [`wget`](https://linux.die.net/man/1/wget) command, run `nano basic-install.sh` to open the file in a text viewer.
If you wish to read over the script before running it, then after the `wget` command, do `nano basic-install.sh` to open a text viewer
Once installed, [configure your router to have **DHCP clients use the Pi as their DNS server**](http://pi-hole.net/faq/can-i-set-the-pi-hole-to-be-the-dns-server-at-my-router-so-i-dont-have-to-change-settings-for-my-devices/) and then any device that connects to your network will have ads blocked without any further configuration. Alternatively, you can manually set each device to [use the Raspberry Pi as its DNS server](http://pi-hole.net/faq/how-do-i-use-the-pi-hole-as-my-dns-server/). Once installed, [configure your router to have **DHCP clients use the Pi as their DNS server**](http://pi-hole.net/faq/can-i-set-the-pi-hole-to-be-the-dns-server-at-my-router-so-i-dont-have-to-change-settings-for-my-devices/) and then any device that connects to your network will have ads blocked without any further configuration. Alternatively, you can manually set each device to [use the Raspberry Pi as its DNS server](http://pi-hole.net/faq/how-do-i-use-the-pi-hole-as-my-dns-server/).
@ -34,7 +32,7 @@ Once installed, [configure your router to have **DHCP clients use the Pi as thei
## Pi-hole Is Free, But Powered By Your Donations ## Pi-hole Is Free, But Powered By Your Donations
Send a one-time donation or sign up for Optimal.com's service using our link below to provide us with a small portion of the monthly fee. Send a one-time donation using our link below to provide us with a small portion of the monthly fee.
- ![Paypal](http://i.imgur.com/3muNfxu.png) : [Donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY) - ![Paypal](http://i.imgur.com/3muNfxu.png) : [Donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY)
- ![Flattr](http://i.imgur.com/ZFceFRu.png) : [Donate](https://flattr.com/submit/auto?user_id=jacobsalmela&url=https://github.com/pi-hole/pi-hole) - ![Flattr](http://i.imgur.com/ZFceFRu.png) : [Donate](https://flattr.com/submit/auto?user_id=jacobsalmela&url=https://github.com/pi-hole/pi-hole)
@ -43,19 +41,24 @@ Send a one-time donation or sign up for Optimal.com's service using our link bel
## Get Help Or Connect With Us On The Web ## Get Help Or Connect With Us On The Web
- [@The_Pi_Hole](https://twitter.com/The_Pi_Hole) - [@The_Pi_Hole](https://twitter.com/The_Pi_Hole)
- [Discourse](https://discourse.pi-hole.net/)
- [/r/pihole](https://www.reddit.com/r/pihole/) - [/r/pihole](https://www.reddit.com/r/pihole/)
- [Pi-hole YouTube channel](https://www.youtube.com/channel/UCT5kq9w0wSjogzJb81C9U0w) - [Pi-hole YouTube channel](https://www.youtube.com/channel/UCT5kq9w0wSjogzJb81C9U0w)
- [Wiki](https://github.com/pi-hole/pi-hole/wiki/Customization) - [Wiki](https://github.com/pi-hole/pi-hole/wiki/Customization)
- [FAQs](https://pi-hole.net/help/) - [FAQs](https://discourse.pi-hole.net/c/faqs)
- [![Join the chat at https://gitter.im/pi-hole/pi-hole](https://badges.gitter.im/pi-hole/pi-hole.svg)](https://gitter.im/pi-hole/pi-hole?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - [![Join the chat at https://gitter.im/pi-hole/pi-hole](https://badges.gitter.im/pi-hole/pi-hole.svg)](https://gitter.im/pi-hole/pi-hole?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Technical Details ## Technical Details
The Pi-hole is an **advertising-aware DNS/Web server**. If an ad domain is queried, a small Web page or GIF is delivered in place of the advertisement. You can also [replace ads with any image you want](http://pi-hole.net/faq/is-it-possible-to-change-the-blank-page-that-takes-place-of-the-ads-to-something-else/) since it is just a simple Webpage taking place of the ads. The Pi-hole is an **advertising-aware DNS/Web server**. If an ad domain is queried, a small Web page or GIF is delivered in place of the advertisement. You can also [replace ads with any image you want](http://pi-hole.net/faq/is-it-possible-to-change-the-blank-page-that-takes-place-of-the-ads-to-something-else/) since it is just a simple Webpage taking place of the ads.
#### Other Operating Systems
This script will work for other UNIX-like systems with some slight **modifications**. As long as you can install `dnsmasq` and a Webserver, it should work OK. The automated install is only for a clean install of a Debian family or Fedora based system, such as the Raspberry Pi. If there are other platforms you'd like supported, let us know.
### Gravity ### Gravity
The [gravity.sh](https://github.com/pi-hole/pi-hole/blob/master/gravity.sh) does most of the magic. The script pulls in ad domains from many sources and compiles them into a single list of [over 1.6 million entries](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0) (if you decide to use the [mahakala list](https://github.com/pi-hole/pi-hole/commit/963eacfe0537a7abddf30441c754c67ca1e40965)). The [gravity.sh](https://github.com/pi-hole/pi-hole/blob/master/gravity.sh) does most of the magic. The script pulls in ad domains from many sources and compiles them into a single list of [over 1.6 million entries](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0) (if you decide to use the [mahakala list](https://github.com/pi-hole/pi-hole/commit/963eacfe0537a7abddf30441c754c67ca1e40965)). This script is controlled by the `pihole` command. Please run `pihole -h` to see what commands can be run via `pihole`.
## Web Interface ## Web Interface
@ -67,13 +70,13 @@ The [Web interface](https://github.com/jacobsalmela/AdminLTE#pi-hole-admin-dashb
### Whitelist and blacklist ### Whitelist and blacklist
Domains can be whitelisted and blacklisted using two pre-installed scripts. See [the wiki page](https://github.com/pi-hole/pi-hole/wiki/Whitelisting-and-Blacklisting) for more details ![Whitelist editor in the Web interface](http://i.imgur.com/ogu2ewg.png) Domains can be whitelisted and blacklisted using either the web interface or the command line. See [the wiki page](https://github.com/pi-hole/pi-hole/wiki/Whitelisting-and-Blacklisting) for more details ![Whitelist editor in the Web interface](http://i.imgur.com/ogu2ewg.png)
## API ## API
A basic read-only API can be accessed at `/admin/api.php`. It returns the following JSON: A basic read-only API can be accessed at `/admin/api.php`. It returns the following JSON:
```json ``` json
{ {
"domains_being_blocked": "136708", "domains_being_blocked": "136708",
"dns_queries_today": "18108", "dns_queries_today": "18108",
@ -119,7 +122,3 @@ You can view [real-time stats](http://pi-hole.net/faq/install-the-real-time-lcd-
- [Foolish Tech Show](https://youtu.be/bYyena0I9yc?t=2m4s) - [Foolish Tech Show](https://youtu.be/bYyena0I9yc?t=2m4s)
- [Pi-hole on Ubuntu](http://www.boyter.org/2015/12/pi-hole-ubuntu-14-04/) - [Pi-hole on Ubuntu](http://www.boyter.org/2015/12/pi-hole-ubuntu-14-04/)
- [Catchpoint: iOS 9 Ad Blocking](http://blog.catchpoint.com/2015/09/14/ad-blocking-apple/) - [Catchpoint: iOS 9 Ad Blocking](http://blog.catchpoint.com/2015/09/14/ad-blocking-apple/)
## Other Operating Systems
This script will work for other UNIX-like systems with some slight **modifications**. As long as you can install `dnsmasq` and a Webserver, it should work OK. The automated install is only for a clean install of a Debian based system, such as the Raspberry Pi.

@ -1,4 +1,4 @@
## Pi-hole ad-list default sources. Updated 22/05/2016 ######################### ## Pi-hole ad-list default sources. Updated 29/10/2016 #########################
# # # #
# To make changes to this file: # # To make changes to this file: #
# 1. run `cp /etc/pihole/adlists.default /etc/pihole/adlists.list` # # 1. run `cp /etc/pihole/adlists.default /etc/pihole/adlists.list` #
@ -42,9 +42,6 @@ https://raw.githubusercontent.com/quidsup/notrack/master/trackers.txt
# Block the BBC News website Breaking News banner # Block the BBC News website Breaking News banner
#https://raw.githubusercontent.com/BreakingTheNews/BreakingTheNews.github.io/master/hosts #https://raw.githubusercontent.com/BreakingTheNews/BreakingTheNews.github.io/master/hosts
# List of known C&C malware servers (see https://github.com/pi-hole/pi-hole/issues/528)
https://ransomwaretracker.abuse.ch/downloads/RW_DOMBL.txt
# Untested Lists: # Untested Lists:
#https://raw.githubusercontent.com/reek/anti-adblock-killer/master/anti-adblock-killer-filters.txt #https://raw.githubusercontent.com/reek/anti-adblock-killer/master/anti-adblock-killer-filters.txt
#https://raw.githubusercontent.com/Dawsey21/Lists/master/main-blacklist.txt #https://raw.githubusercontent.com/Dawsey21/Lists/master/main-blacklist.txt

@ -9,53 +9,41 @@
# the Free Software Foundation, either version 2 of the License, or # the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# If you want dnsmasq to read another file, as well as /etc/hosts, use ###############################################################################
# this. # FILE AUTOMATICALLY POPULATED BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
addn-hosts=/etc/pihole/gravity.list # ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
# #
# IF YOU WISH TO CHANGE THE UPSTREAM SERVERS, CHANGE THEM IN: #
# /etc/pihole/setupVars.conf #
# #
# ANY OTHER CHANGES SHOULD BE MADE IN A SEPERATE CONFIG FILE #
# OR IN /etc/dnsmasq.conf #
###############################################################################
address=/pi.hole/@IPv4@
address=/pi.hole/@IPv6@
address=/@HOSTNAME@/@IPv4@
address=/@HOSTNAME@/@IPv6@
# The following two options make you a better netizen, since they addn-hosts=/etc/pihole/gravity.list
# tell dnsmasq to filter out queries which the public DNS cannot
# answer, and which load the servers (especially the root servers)
# unnecessarily. If you have a dial-on-demand link they also stop
# these requests from bringing up the link unnecessarily.
# Never forward plain names (without a dot or domain part)
domain-needed domain-needed
# Never forward addresses in the non-routed address spaces.
bogus-priv bogus-priv
# If you don't want dnsmasq to read /etc/resolv.conf or any other
# file, getting its servers from this file instead (see below), then
# uncomment this.
no-resolv no-resolv
# Add other name servers here, with domain specs if they are for
# non-public domains.
server=@DNS1@ server=@DNS1@
server=@DNS2@ server=@DNS2@
# If you want dnsmasq to listen for DHCP and DNS requests only on
# specified interfaces (and the loopback) give the name of the
# interface (eg eth0) here.
interface=@INT@ interface=@INT@
# Or which to listen on by address (remember to include 127.0.0.1 if
# you use this.)
listen-address=127.0.0.1
# Set the cachesize here.
cache-size=10000 cache-size=10000
# For debugging purposes, log each DNS query as it passes through
# dnsmasq.
log-queries log-queries
log-facility=/var/log/pihole.log log-facility=/var/log/pihole.log
# Normally responses which come from /etc/hosts and the DHCP lease
# file have Time-To-Live set as zero, which conventionally means
# do not cache further. If you are happy to trade lower load on the
# server for potentially stale date, you can set a time-to-live (in
# seconds) here.
local-ttl=300 local-ttl=300
# This allows it to continue functioning without being blocked by syslog, and allows syslog to use dnsmasq for DNS queries without risking deadlock
log-async log-async

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

@ -17,11 +17,11 @@ gravity="/etc/pihole/gravity.list"
today=$(date "+%b %e") today=$(date "+%b %e")
function CalcBlockedDomains(){ CalcBlockedDomains() {
CheckIPv6 CheckIPv6
if [ -e "$gravity" ]; then if [ -e "${gravity}" ]; then
#Are we IPV6 or IPV4? #Are we IPV6 or IPV4?
if [[ -n ${piholeIPv6} ]];then if [[ -n ${piholeIPv6} ]]; then
#We are IPV6 #We are IPV6
blockedDomainsTotal=$(wc -l /etc/pihole/gravity.list | awk '{print $1/2}') blockedDomainsTotal=$(wc -l /etc/pihole/gravity.list | awk '{print $1/2}')
else else
@ -33,35 +33,35 @@ function CalcBlockedDomains(){
fi fi
} }
function CalcQueriesToday(){ CalcQueriesToday() {
if [ -e "$piLog" ];then if [ -e "${piLog}" ]; then
queriesToday=$(cat "$piLog" | grep "$today" | awk '/query/ {print $6}' | wc -l) queriesToday=$(cat "${piLog}" | grep "${today}" | awk '/query/ {print $6}' | wc -l)
else else
queriesToday="Err." queriesToday="Err."
fi fi
} }
function CalcblockedToday(){ CalcblockedToday() {
if [ -e "$piLog" ] && [ -e "$gravity" ];then if [ -e "${piLog}" ] && [ -e "${gravity}" ];then
blockedToday=$(cat ${piLog} | awk '/\/etc\/pihole\/gravity.list/ && !/address/ {print $6}' | wc -l) blockedToday=$(cat ${piLog} | awk '/\/etc\/pihole\/gravity.list/ && !/address/ {print $6}' | wc -l)
else else
blockedToday="Err." blockedToday="Err."
fi fi
} }
function CalcPercentBlockedToday(){ CalcPercentBlockedToday() {
if [ "$queriesToday" != "Err." ] && [ "$blockedToday" != "Err." ]; then if [ "${queriesToday}" != "Err." ] && [ "${blockedToday}" != "Err." ]; then
if [ "$queriesToday" != 0 ]; then #Fixes divide by zero error :) if [ "${queriesToday}" != 0 ]; then #Fixes divide by zero error :)
#scale 2 rounds the number down, so we'll do scale 4 and then trim the last 2 zeros #scale 2 rounds the number down, so we'll do scale 4 and then trim the last 2 zeros
percentBlockedToday=$(echo "scale=4; $blockedToday/$queriesToday*100" | bc) percentBlockedToday=$(echo "scale=4; ${blockedToday}/${queriesToday}*100" | bc)
percentBlockedToday=$(sed 's/.\{2\}$//' <<< "$percentBlockedToday") percentBlockedToday=$(sed 's/.\{2\}$//' <<< "${percentBlockedToday}")
else else
percentBlockedToday=0 percentBlockedToday=0
fi fi
fi fi
} }
function CheckIPv6(){ CheckIPv6() {
piholeIPv6file="/etc/pihole/.useIPv6" piholeIPv6file="/etc/pihole/.useIPv6"
if [[ -f ${piholeIPv6file} ]];then if [[ -f ${piholeIPv6file} ]];then
# If the file exists, then the user previously chose to use IPv6 in the automated installer # If the file exists, then the user previously chose to use IPv6 in the automated installer
@ -69,7 +69,7 @@ function CheckIPv6(){
fi fi
} }
function outputJSON(){ outputJSON() {
CalcQueriesToday CalcQueriesToday
CalcblockedToday CalcblockedToday
CalcPercentBlockedToday CalcPercentBlockedToday
@ -79,9 +79,8 @@ function outputJSON(){
printf '{"domains_being_blocked":"%s","dns_queries_today":"%s","ads_blocked_today":"%s","ads_percentage_today":"%s"}\n' "$blockedDomainsTotal" "$queriesToday" "$blockedToday" "$percentBlockedToday" printf '{"domains_being_blocked":"%s","dns_queries_today":"%s","ads_blocked_today":"%s","ads_percentage_today":"%s"}\n' "$blockedDomainsTotal" "$queriesToday" "$blockedToday" "$percentBlockedToday"
} }
function normalChrono(){ normalChrono() {
for (( ; ; )) for (( ; ; )); do
do
clear clear
# Displays a colorful Pi-hole logo # Displays a colorful Pi-hole logo
echo " ___ _ _ _" echo " ___ _ _ _"
@ -111,26 +110,27 @@ function normalChrono(){
CalcBlockedDomains CalcBlockedDomains
echo "Blocking: $blockedDomainsTotal" echo "Blocking: ${blockedDomainsTotal}"
#below commented line does not add up to todaysQueryCount #below commented line does not add up to todaysQueryCount
#echo "Queries: $todaysQueryCountV4 / $todaysQueryCountV6" #echo "Queries: $todaysQueryCountV4 / $todaysQueryCountV6"
echo "Queries: $queriesToday" #same total calculation as dashboard echo "Queries: ${queriesToday}" #same total calculation as dashboard
echo "Pi-holed: $blockedToday ($percentBlockedToday%)" echo "Pi-holed: ${blockedToday} (${percentBlockedToday}%)"
sleep 5 sleep 5
done done
} }
function displayHelp(){ displayHelp() {
echo "::: Displays stats about your piHole!" cat << EOM
echo ":::" ::: Displays stats about your piHole!
echo "::: Usage: sudo pihole -c [optional:-j]" :::
echo "::: Note: If no option is passed, then stats are displayed on screen, updated every 5 seconds" ::: Usage: sudo pihole -c [optional:-j]
echo ":::" ::: Note: If no option is passed, then stats are displayed on screen, updated every 5 seconds
echo "::: Options:" :::
echo "::: -j, --json output stats as JSON formatted string" ::: Options:
echo "::: -h, --help display this help text" ::: -j, --json output stats as JSON formatted string
::: -h, --help display this help text
EOM
exit 1 exit 1
} }
@ -138,8 +138,7 @@ if [[ $# = 0 ]]; then
normalChrono normalChrono
fi fi
for var in "$@" for var in "$@"; do
do
case "$var" in case "$var" in
"-j" | "--json" ) outputJSON;; "-j" | "--json" ) outputJSON;;
"-h" | "--help" ) displayHelp;; "-h" | "--help" ) displayHelp;;

@ -0,0 +1,166 @@
#!/usr/bin/env bash
# Pi-hole: A black hole for Internet advertisements
# (c) 2015, 2016 by Jacob Salmela
# Network-wide ad blocking via your Raspberry Pi
# http://pi-hole.net
# Whitelists and blacklists domains
#
# Pi-hole is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#globals
basename=pihole
piholeDir=/etc/${basename}
whitelist=${piholeDir}/whitelist.txt
blacklist=${piholeDir}/blacklist.txt
reload=false
addmode=true
verbose=true
domList=()
domToRemoveList=()
listMain=""
listAlt=""
helpFunc() {
if [[ ${listMain} == ${whitelist} ]]; then
letter="w"
word="white"
else
letter="b"
word="black"
fi
cat << EOM
::: Immediately ${word}lists one or more domains in the hosts file
:::
::: Usage: pihole -${letter} domain1 [domain2 ...]
:::
::: Options:
::: -d, --delmode Remove domains from the ${word}list
::: -nr, --noreload Update ${word}list without refreshing dnsmasq
::: -q, --quiet output is less verbose
::: -h, --help Show this help dialog
::: -l, --list Display your ${word}listed domains
EOM
exit 1
}
HandleOther(){
#check validity of domain
validDomain=$(echo "$1" | perl -ne'print if /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/')
if [ -z "${validDomain}" ]; then
echo "::: $1 is not a valid argument or domain name"
else
domList=("${domList[@]}" ${validDomain})
fi
}
PoplistFile() {
#check whitelist file exists, and if not, create it
if [[ ! -f ${whitelist} ]]; then
touch ${whitelist}
fi
for dom in "${domList[@]}"; do
# Logic : If addmode then add to desired list and remove from the other; if delmode then remove from desired list but do not add to the other
if ${addmode}; then
AddDomain "${dom}" "${listMain}"
RemoveDomain "${dom}" "${listAlt}"
else
RemoveDomain "${dom}" "${listMain}"
fi
done
}
AddDomain() {
list="$2"
bool=true
#Is the domain in the list we want to add it to?
grep -Ex -q "$1" ${list} > /dev/null 2>&1 || bool=false
if [[ "${bool}" == false ]]; then
#domain not found in the whitelist file, add it!
if [[ "${verbose}" == true ]]; then
echo "::: Adding $1 to $list..."
fi
reload=true
# Add it to the list we want to add it to
echo "$1" >> ${list}
else
if [[ "${verbose}" == true ]]; then
echo "::: ${1} already exists in ${list}, no need to add!"
fi
fi
}
RemoveDomain() {
list="$2"
bool=true
#Is it in the other list? Logic follows that if its whitelisted it should not be blacklisted and vice versa
grep -Ex -q "$1" ${list} > /dev/null 2>&1 || bool=false
if [[ "${bool}" == true ]]; then
# Remove it from the other one
echo "::: Removing $1 from $list..."
echo "$1" | sed 's/\./\\./g' | xargs -I {} perl -i -ne'print unless /'{}'(?!.)/;' ${list}
reload=true
else
if [[ "${verbose}" == true ]]; then
echo "::: ${1} does not exist in ${list}, no need to remove!"
fi
fi
}
Reload() {
# Reload hosts file
pihole -g -sd
}
Displaylist() {
if [[ ${listMain} == ${whitelist} ]]; then
string="gravity resistant domains"
else
string="domains caught in the sinkhole"
fi
verbose=false
echo -e " Displaying $string \n"
count=1
while IFS= read -r RD; do
echo "${count}: ${RD}"
count=$((count+1))
done < "${listMain}"
exit 0;
}
for var in "$@"; do
case "${var}" in
"-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";;
"-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";;
"-nr"| "--noreload" ) reload=false;;
"-d" | "--delmode" ) addmode=false;;
"-f" | "--force" ) force=true;;
"-q" | "--quiet" ) verbose=false;;
"-h" | "--help" ) helpFunc;;
"-l" | "--list" ) Displaylist;;
* ) HandleOther "${var}";;
esac
done
shift
if [[ $# = 0 ]]; then
helpFunc
fi
PoplistFile
if ${reload}; then
Reload
fi

@ -13,452 +13,381 @@
set -o pipefail set -o pipefail
######## GLOBAL VARS ######## ######## GLOBAL VARS ########
VARSFILE="/etc/pihole/setupVars.conf"
DEBUG_LOG="/var/log/pihole_debug.log" DEBUG_LOG="/var/log/pihole_debug.log"
DNSMASQFILE="/etc/dnsmasq.conf" DNSMASQFILE="/etc/dnsmasq.conf"
PIHOLECONFFILE="/etc/dnsmasq.d/01-pihole.conf" DNSMASQCONFFILE="/etc/dnsmasq.d/01-pihole.conf"
LIGHTTPDFILE="/etc/lighttpd/lighttpd.conf" LIGHTTPDFILE="/etc/lighttpd/lighttpd.conf"
LIGHTTPDERRFILE="/var/log/lighttpd/error.log" LIGHTTPDERRFILE="/var/log/lighttpd/error.log"
GRAVITYFILE="/etc/pihole/gravity.list" GRAVITYFILE="/etc/pihole/gravity.list"
HOSTSFILE="/etc/hosts"
WHITELISTFILE="/etc/pihole/whitelist.txt" WHITELISTFILE="/etc/pihole/whitelist.txt"
BLACKLISTFILE="/etc/pihole/blacklist.txt" BLACKLISTFILE="/etc/pihole/blacklist.txt"
ADLISTSFILE="/etc/pihole/adlists.list" ADLISTFILE="/etc/pihole/adlists.list"
PIHOLELOG="/var/log/pihole.log" PIHOLELOG="/var/log/pihole.log"
WHITELISTMATCHES="/tmp/whitelistmatches.list" WHITELISTMATCHES="/tmp/whitelistmatches.list"
IPV6_READY=false
# Header info and introduction # Header info and introduction
echo "::: Beginning Pi-hole debug at $(date)!" cat << EOM
echo "::: This debugging process will collect information from your running configuration," ::: Beginning Pi-hole debug at $(date)!
echo "::: and optionally upload the generated log to a unique and random directory on" :::
echo "::: Termbin.com. NOTE: All log files auto-delete after 1 month and you are the only" ::: This process collects information from your Pi-hole, and optionally uploads
echo "::: person who is given the unique URL. Please consider where you post this link." ::: it to a unique and random directory on tricorder.pi-hole.net.
echo "::: " :::
::: NOTE: All log files auto-delete after 24 hours and ONLY the Pi-hole developers
::: can access your data via the given token. We have taken these extra steps to
######## FIRST CHECK ######## ::: secure your data and will work to further reduce any personal information gathered.
# Must be root to debug :::
if [[ "$EUID" -eq 0 ]]; then ::: Please read and note any issues, and follow any directions advised during this process.
echo "::: Script is executing as root user..." EOM
else
echo "::: Non-root user detected..."
# Check if sudo is actually installed
if [ -x "$(command -v sudo)" ]; then
export SUDO="sudo"
echo "::: sudo command located, debug will run under sudo."
else
echo "::: Unable to locate sudo command. Please install sudo or run this as root."
exit 1
fi
fi
# Ensure the file exists, create if not, clear if exists. # Ensure the file exists, create if not, clear if exists.
if [ ! -f "$DEBUG_LOG" ]; then truncate --size=0 "${DEBUG_LOG}"
${SUDO} touch ${DEBUG_LOG} chmod 644 ${DEBUG_LOG}
${SUDO} chmod 644 ${DEBUG_LOG} chown "$USER":pihole ${DEBUG_LOG}
${SUDO} chown "$USER":root ${DEBUG_LOG}
else source ${VARSFILE}
truncate -s 0 ${DEBUG_LOG}
fi
### Private functions exist here ### ### Private functions exist here ###
function log_write { log_write() {
echo "$1" >> "${DEBUG_LOG}" echo "${1}" >> "${DEBUG_LOG}"
} }
function version_check { log_echo() {
log_write "############################################################" case ${1} in
log_write "########## Installed Versions ##########" -n)
log_write "############################################################" echo -n "::: ${2}"
log_write "${2}"
;;
-r)
echo "::: ${2}"
log_write "${2}"
;;
-l)
echo "${2}"
log_write "${2}"
;;
*)
echo "::: ${1}"
log_write "${1}"
esac
}
echo "::: Detecting Pi-hole installed versions." header_write() {
pi_hole_ver="$(cd /etc/.pihole/ && git describe --tags --abbrev=0)" \ log_echo ""
&& log_write "Pi-hole Version: $pi_hole_ver" || log_write "Pi-hole git repository not detected." log_echo "${1}"
admin_ver="$(cd /var/www/html/admin && git describe --tags --abbrev=0)" \ log_write ""
&& log_write "WebUI Version: $admin_ver" || log_write "Pi-hole Admin Pages git repository not detected." }
echo "::: Writing lighttpd version to logfile." file_parse() {
light_ver="$(lighttpd -v |& head -n1)" && log_write "${light_ver}" || log_write "lighttpd not installed." while read -r line; do
if [ ! -z "${line}" ]; then
[[ "${line}" =~ ^#.*$ || ! "${line}" ]] && continue
log_write "${line}"
fi
done < "${1}"
log_write ""
}
echo "::: Writing PHP version to logfile." block_parse() {
php_ver="$(php -v |& head -n1)" && log_write "${php_ver}" || log_write "PHP not installed." log_write "${1}"
} }
function distro_check { lsof_parse() {
echo "############################################################" >> ${DEBUG_LOG} local user
echo "######## Installed OS Distribution #########" >> ${DEBUG_LOG} local process
echo "############################################################" >> ${DEBUG_LOG}
echo "::: Checking installed OS Distribution release." user=$(echo ${1} | cut -f 3 -d ' ' | cut -c 2-)
TMP=$(cat /etc/*release || echo "Failed to find release") process=$(echo ${1} | cut -f 2 -d ' ' | cut -c 2-)
[[ ${2} -eq ${process} ]] \
&& echo "::: Correctly configured." \
|| log_echo "::: Failure: Incorrectly configured daemon."
echo "::: Writing OS Distribution release to logfile." log_write "Found user ${user} with process ${process}"
echo "$TMP" >> ${DEBUG_LOG}
echo >> ${DEBUG_LOG}
} }
function ip_check {
echo "############################################################" >> ${DEBUG_LOG}
echo "######## IP Address Information #########" >> ${DEBUG_LOG}
echo "############################################################" >> ${DEBUG_LOG}
echo "::: Writing local IPs to logfile"
IPADDR="$(ip a | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "inet") print $(i+1) }')"
echo "$IPADDR" >> ${DEBUG_LOG}
IP6ADDR="$(ip a | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "inet6") print $(i+1) }')" \
&& echo "$IP6ADDR" >> ${DEBUG_LOG} || echo "No IPv6 addresses found." >> ${DEBUG_LOG}
echo >> ${DEBUG_LOG}
echo "::: Locating default gateway and checking connectivity"
GATEWAY=$(ip r | grep default | cut -d ' ' -f 3)
if [[ $? = 0 ]]
then
echo "::: Pinging default IPv4 gateway..."
GATEWAY_CHECK=$(ping -q -w 3 -c 3 -n "${GATEWAY}" | tail -n3)
if [[ $? = 0 ]]
then
echo "IPv4 Gateway check:" >> ${DEBUG_LOG}
else
echo "IPv4 Gateway check failed:" >> ${DEBUG_LOG}
fi
echo "$GATEWAY_CHECK" >> ${DEBUG_LOG}
echo >> ${DEBUG_LOG}
echo "::: Pinging Internet via IPv4..."
INET_CHECK=$(ping -q -w 5 -c 3 -n 8.8.8.8 | tail -n3)
if [[ $? = 0 ]]
then
echo "IPv4 Internet check:" >> ${DEBUG_LOG}
else
echo "IPv4 Internet check failed:" >> ${DEBUG_LOG}
fi
echo "$INET_CHECK" >> ${DEBUG_LOG}
echo >> ${DEBUG_LOG}
fi
GATEWAY6=$(ip -6 r | grep default | cut -d ' ' -f 3) version_check() {
if [[ $? = 0 ]] header_write "Detecting Installed Package Versions:"
then
echo "::: Pinging default IPv6 gateway..."
GATEWAY6_CHECK=$(ping6 -q -w 3 -c 3 -n "${GATEWAY6}" | tail -n3)
if [[ $? = 0 ]]
then
echo "IPv6 Gateway check:" >> ${DEBUG_LOG}
else
echo "IPv6 Gateway check failed:" >> ${DEBUG_LOG}
fi
echo "::: Pinging Internet via IPv6..." local error_found
GATEWAY6_CHECK=$(ping6 -q -w 3 -c 3 -n 2001:4860:4860::8888 | tail -n3) error_found=0
if [[ $? = 0 ]]
then local pi_hole_ver="$(cd /etc/.pihole/ && git describe --tags --abbrev=0)" \
echo "IPv6 Internet check:" >> ${DEBUG_LOG} && log_echo -r "Pi-hole: $pi_hole_ver" || (log_echo "Pi-hole git repository not detected." && error_found=1)
else local admin_ver="$(cd /var/www/html/admin && git describe --tags --abbrev=0)" \
echo "IPv6 Internet check failed:" >> ${DEBUG_LOG} && log_echo -r "WebUI: $admin_ver" || (log_echo "Pi-hole Admin Pages git repository not detected." && error_found=1)
fi local light_ver="$(lighttpd -v |& head -n1 | cut -d " " -f1)" \
&& log_echo -r "${light_ver}" || (log_echo "lighttpd not installed." && error_found=1)
local php_ver="$(php -v |& head -n1)" \
&& log_echo -r "${php_ver}" || (log_echo "PHP not installed." && error_found=1)
return "${error_found}"
}
files_check() {
#Check non-zero length existence of ${1}
header_write "Detecting existence of ${1}:"
local search_file="${1}"
if [[ -s ${search_file} ]]; then
echo "::: File exists"
file_parse "${search_file}"
return 0
else else
GATEWAY_CHECK="No IPv6 Gateway Detected" log_echo "${1} not found!"
return 1
fi fi
echo "$GATEWAY_CHECK" >> ${DEBUG_LOG} echo ":::"
}
source_file() {
local file_found=$(files_check "${1}") \
&& (source "${1}" &> /dev/null && echo "${file_found} and was successfully sourced") \
|| log_echo -l "${file_found} and could not be sourced"
}
echo >> ${DEBUG_LOG} distro_check() {
local soft_fail
header_write "Detecting installed OS Distribution"
soft_fail=0
local distro="$(cat /etc/*release)" && block_parse "${distro}" || (log_echo "Distribution details not found." && soft_fail=1)
return "${soft_fail}"
} }
function hostnameCheck { processor_check() {
echo "############################################################" >> ${DEBUG_LOG} header_write "Checking processor variety"
echo "######## Hostname Information #########" >> ${DEBUG_LOG} log_write $(uname -m) && return 0 || return 1
echo "############################################################" >> ${DEBUG_LOG} }
echo "::: Writing locally configured hostnames to logfile" ipv6_check() {
# Write the hostname output to compare against entries in /etc/hosts, which is logged next # Check if system is IPv6 enabled, for use in other functions
echo "This Pi-hole is: $(hostname)" >> ${DEBUG_LOG} if [[ $IPv6_address ]]; then
ls /proc/net/if_inet6 &>/dev/null && IPV6_READY=true
return 0
else
return 1
fi
}
echo "::: Writing hosts file to debug log..."
echo "### Hosts ###" >> ${DEBUG_LOG}
if [ -e "$HOSTSFILE" ] ip_check() {
then header_write "IP Address Information"
cat "$HOSTSFILE" >> ${DEBUG_LOG} # Get the current interface for Internet traffic
echo >> ${DEBUG_LOG}
# Check if IPv6 enabled
local IPv6_interface
local IPv4_interface
ipv6_check && IPv6_interface=${piholeInterface:-$(ip -6 r | grep default | cut -d ' ' -f 5)}
# If declared in setupVars.conf use it, otherwise defer to default
# http://stackoverflow.com/questions/2013547/assigning-default-values-to-shell-variables-with-a-single-command-in-bash
IPv4_interface=${piholeInterface:-$(ip r | grep default | cut -d ' ' -f 5)}
if [[ IPV6_READY ]]; then
local IPv6_addr_list="$(ip a | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "inet6") print $(i+1) }')" \
&& (log_write "${IPv6_addr_list}" && echo "::: IPv6 addresses located") \
|| log_echo "No IPv6 addresses found."
local IPv6_def_gateway=$(ip -6 r | grep default | cut -d ' ' -f 3)
if [[ $? = 0 ]] && [[ -n ${IPv6_def_gateway} ]]; then
echo -n "::: Pinging default IPv6 gateway: "
local IPv6_def_gateway_check="$(ping6 -q -W 3 -c 3 -n "${IPv6_def_gateway}" -I "${IPv6_interface}"| tail -n3)" \
&& echo "Gateway Responded." \
|| echo "Gateway did not respond."
block_parse "${IPv6_def_gateway_check}"
echo -n "::: Pinging Internet via IPv6: "
local IPv6_inet_check=$(ping6 -q -W 3 -c 3 -n 2001:4860:4860::8888 -I "${IPv6_interface}"| tail -n3) \
&& echo "Query responded." \
|| echo "Query did not respond."
block_parse "${IPv6_inet_check}"
else else
echo "No hosts file found!" >> ${DEBUG_LOG} log_echo="No IPv6 Gateway Detected"
printf ":::\tNo hosts file found!\n" fi
local IPv4_addr_list="$(ip a | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "inet") print $(i+1) }')" \
&& (block_parse "${IPv4_addr_list}" && echo "::: IPv4 addresses located")\
|| log_echo "No IPv4 addresses found."
local IPv4_def_gateway=$(ip r | grep default | cut -d ' ' -f 3)
if [[ $? = 0 ]]; then
echo -n "::: Pinging default IPv4 gateway: "
local IPv4_def_gateway_check="$(ping -q -w 3 -c 3 -n "${IPv4_def_gateway}" -I "${IPv4_interface}" | tail -n3)" \
&& echo "Gateway responded." \
|| echo "Gateway did not respond."
block_parse "${IPv4_def_gateway_check}"
echo -n "::: Pinging Internet via IPv4: "
local IPv4_inet_check="$(ping -q -w 5 -c 3 -n 8.8.8.8 -I "${IPv4_interface}" | tail -n3)" \
&& echo "Query responded." \
|| echo "Query did not respond."
block_parse "${IPv4_inet_check}"
fi fi
}
function portCheck { fi
echo "############################################################" >> ${DEBUG_LOG} }
echo "######## Open Port Information #########" >> ${DEBUG_LOG}
echo "############################################################" >> ${DEBUG_LOG}
echo "::: Detecting local server port 80 and 53 processes." port_check() {
local lsof_value
${SUDO} lsof -i :80 >> ${DEBUG_LOG} lsof_value=$(lsof -i ${1}:${2} -FcL | tr '\n' ' ') \
${SUDO} lsof -i :53 >> ${DEBUG_LOG} && lsof_parse "${lsof_value}" "${3}" \
echo >> ${DEBUG_LOG} || log_echo "Failure: IPv${1} Port not in use"
} }
function testResolver { daemon_check() {
echo "############################################################" >> ${DEBUG_LOG} # Check for daemon ${1} on port ${2}
echo "############ Resolver Functions Check ############" >> ${DEBUG_LOG} header_write "Daemon Process Information"
echo "############################################################" >> ${DEBUG_LOG}
echo "::: Checking ${2} port for ${1} listener."
if [[ ${IPV6_READY} ]]; then
port_check 6 "${2}" "${1}"
fi
lsof_value=$(lsof -i 4:${2} -FcL | tr '\n' ' ') \
port_check 4 "${2}" "${1}"
}
testResolver() {
header_write "Resolver Functions Check"
# Find a blocked url that has not been whitelisted. # Find a blocked url that has not been whitelisted.
TESTURL="doubleclick.com" TESTURL="doubleclick.com"
if [ -s "$WHITELISTMATCHES" ]; then if [ -s "${WHITELISTMATCHES}" ]; then
while read -r line; do while read -r line; do
CUTURL=${line#*" "} CUTURL=${line#*" "}
if [ "$CUTURL" != "Pi-Hole.IsWorking.OK" ]; then if [ "${CUTURL}" != "Pi-Hole.IsWorking.OK" ]; then
while read -r line2; do while read -r line2; do
CUTURL2=${line2#*" "} CUTURL2=${line2#*" "}
if [ "$CUTURL" != "$CUTURL2" ]; then if [ "${CUTURL}" != "${CUTURL2}" ]; then
TESTURL="$CUTURL" TESTURL="${CUTURL}"
break 2 break 2
fi fi
done < "$WHITELISTMATCHES" done < "${WHITELISTMATCHES}"
fi fi
done < "$GRAVITYFILE" done < "${GRAVITYFILE}"
fi fi
echo "Resolution of $TESTURL from Pi-hole:" >> ${DEBUG_LOG} log_write "Resolution of ${TESTURL} from Pi-hole:"
LOCALDIG=$(dig "$TESTURL" @127.0.0.1) LOCALDIG=$(dig "${TESTURL}" @127.0.0.1)
if [[ $? = 0 ]] if [[ $? = 0 ]]; then
then log_write "${LOCALDIG}"
echo "$LOCALDIG" >> ${DEBUG_LOG}
else else
echo "Failed to resolve $TESTURL on Pi-hole" >> ${DEBUG_LOG} log_write "Failed to resolve ${TESTURL} on Pi-hole"
fi fi
echo >> ${DEBUG_LOG} log_write ""
echo "Resolution of $TESTURL from 8.8.8.8:" >> ${DEBUG_LOG} log_write "Resolution of ${TESTURL} from 8.8.8.8:"
REMOTEDIG=$(dig "$TESTURL" @8.8.8.8) REMOTEDIG=$(dig "${TESTURL}" @8.8.8.8)
if [[ $? = 0 ]] if [[ $? = 0 ]]; then
then log_write "${REMOTEDIG}"
echo "$REMOTEDIG" >> ${DEBUG_LOG}
else else
echo "Failed to resolve $TESTURL on 8.8.8.8" >> ${DEBUG_LOG} log_write "Failed to resolve ${TESTURL} on 8.8.8.8"
fi fi
echo >> ${DEBUG_LOG} log_write ""
echo "Pi-hole dnsmasq specific records lookups" >> ${DEBUG_LOG} log_write "Pi-hole dnsmasq specific records lookups"
echo "Cache Size:" >> ${DEBUG_LOG} log_write "Cache Size:"
dig +short chaos txt cachesize.bind >> ${DEBUG_LOG} dig +short chaos txt cachesize.bind >> ${DEBUG_LOG}
echo "Insertions count:" >> ${DEBUG_LOG} log_write "Upstream Servers:"
dig +short chaos txt insertions.bind >> ${DEBUG_LOG}
echo "Evictions count:" >> ${DEBUG_LOG}
dig +short chaos txt evictions.bind >> ${DEBUG_LOG}
echo "Misses count:" >> ${DEBUG_LOG}
dig +short chaos txt misses.bind >> ${DEBUG_LOG}
echo "Hits count:" >> ${DEBUG_LOG}
dig +short chaos txt hits.bind >> ${DEBUG_LOG}
echo "Auth count:" >> ${DEBUG_LOG}
dig +short chaos txt auth.bind >> ${DEBUG_LOG}
echo "Upstream Servers:" >> ${DEBUG_LOG}
dig +short chaos txt servers.bind >> ${DEBUG_LOG} dig +short chaos txt servers.bind >> ${DEBUG_LOG}
echo >> ${DEBUG_LOG} log_write ""
} }
function checkProcesses { checkProcesses() {
echo "#######################################" >> ${DEBUG_LOG} header_write "Processes Check"
echo "########### Processes Check ###########" >> ${DEBUG_LOG}
echo "#######################################" >> ${DEBUG_LOG}
echo ":::"
echo "::: Logging status of lighttpd and dnsmasq..." echo "::: Logging status of lighttpd and dnsmasq..."
PROCESSES=( lighttpd dnsmasq ) PROCESSES=( lighttpd dnsmasq )
for i in "${PROCESSES[@]}" for i in "${PROCESSES[@]}"; do
do log_write ""
echo "" >> ${DEBUG_LOG} log_write "${i}"
echo -n "$i" >> "$DEBUG_LOG" log_write " processes status:"
echo " processes status:" >> ${DEBUG_LOG} systemctl -l status "${i}" >> "${DEBUG_LOG}"
${SUDO} systemctl -l status "$i" >> "$DEBUG_LOG"
done done
echo >> ${DEBUG_LOG} log_write ""
} }
function debugLighttpd { debugLighttpd() {
echo "::: Writing lighttpd to debug log..." echo "::: Checking for necessary lighttpd files."
echo "#######################################" >> ${DEBUG_LOG} files_check "${LIGHTTPDFILE}"
echo "############ lighttpd.conf ############" >> ${DEBUG_LOG} files_check "${LIGHTTPDERRFILE}"
echo "#######################################" >> ${DEBUG_LOG} echo ":::"
if [ -e "$LIGHTTPDFILE" ]
then
while read -r line; do
if [ ! -z "$line" ]; then
[[ "$line" =~ ^#.*$ ]] && continue
echo "$line" >> ${DEBUG_LOG}
fi
done < "$LIGHTTPDFILE"
echo >> ${DEBUG_LOG}
else
echo "No lighttpd.conf file found!" >> ${DEBUG_LOG}
printf ":::\tNo lighttpd.conf file found\n"
fi
if [ -e "$LIGHTTPDERRFILE" ]
then
echo "#######################################" >> ${DEBUG_LOG}
echo "######### lighttpd error.log ##########" >> ${DEBUG_LOG}
echo "#######################################" >> ${DEBUG_LOG}
cat "$LIGHTTPDERRFILE" >> ${DEBUG_LOG}
else
echo "No lighttpd error.log file found!" >> ${DEBUG_LOG}
printf ":::\tNo lighttpd error.log file found\n"
fi
echo >> ${DEBUG_LOG}
} }
### END FUNCTIONS ### ### END FUNCTIONS ###
version_check # Gather version of required packages / repositories
distro_check version_check || echo "REQUIRED FILES MISSING"
# Check for newer setupVars storage file
source_file "/etc/pihole/setupVars.conf"
# Gather information about the running distribution
distro_check || echo "Distro Check soft fail"
# Gather processor type
processor_check || echo "Processor Check soft fail"
ip_check ip_check
hostnameCheck
portCheck daemon_check lighttpd http
daemon_check dnsmasq domain
checkProcesses checkProcesses
testResolver testResolver
debugLighttpd debugLighttpd
echo "::: Writing dnsmasq.conf to debug log..." files_check "${DNSMASQFILE}"
echo "#######################################" >> ${DEBUG_LOG} files_check "${DNSMASQCONFFILE}"
echo "############### Dnsmasq ###############" >> ${DEBUG_LOG} files_check "${WHITELISTFILE}"
echo "#######################################" >> ${DEBUG_LOG} files_check "${BLACKLISTFILE}"
if [ -e "$DNSMASQFILE" ] files_check "${ADLISTFILE}"
then
#cat $DNSMASQFILE >> $DEBUG_LOG
while read -r line; do
if [ ! -z "$line" ]; then
[[ "$line" =~ ^#.*$ ]] && continue
echo "$line" >> ${DEBUG_LOG}
fi
done < "$DNSMASQFILE"
echo >> ${DEBUG_LOG}
else
echo "No dnsmasq.conf file found!" >> ${DEBUG_LOG}
printf ":::\tNo dnsmasq.conf file found!\n"
fi
echo "::: Writing 01-pihole.conf to debug log..."
echo "#######################################" >> ${DEBUG_LOG}
echo "########### 01-pihole.conf ############" >> ${DEBUG_LOG}
echo "#######################################" >> ${DEBUG_LOG}
if [ -e "$PIHOLECONFFILE" ]
then
while read -r line; do
if [ ! -z "$line" ]; then
[[ "$line" =~ ^#.*$ ]] && continue
echo "$line" >> ${DEBUG_LOG}
fi
done < "$PIHOLECONFFILE"
echo >> ${DEBUG_LOG}
else
echo "No 01-pihole.conf file found!" >> ${DEBUG_LOG}
printf ":::\tNo 01-pihole.conf file found\n"
fi
echo "::: Writing size of gravity.list to debug log..."
echo "#######################################" >> ${DEBUG_LOG}
echo "############ gravity.list #############" >> ${DEBUG_LOG}
echo "#######################################" >> ${DEBUG_LOG}
if [ -e "$GRAVITYFILE" ]
then
wc -l "$GRAVITYFILE" >> ${DEBUG_LOG}
echo >> ${DEBUG_LOG}
else
echo "No gravity.list file found!" >> ${DEBUG_LOG}
printf ":::\tNo gravity.list file found\n"
fi
### Pi-hole application specific logging ###
echo "::: Writing whitelist to debug log..."
echo "#######################################" >> ${DEBUG_LOG}
echo "############## Whitelist ##############" >> ${DEBUG_LOG}
echo "#######################################" >> ${DEBUG_LOG}
if [ -e "$WHITELISTFILE" ]
then
cat "$WHITELISTFILE" >> ${DEBUG_LOG}
echo >> ${DEBUG_LOG}
else
echo "No whitelist.txt file found!" >> ${DEBUG_LOG}
printf ":::\tNo whitelist.txt file found!\n"
fi
echo "::: Writing blacklist to debug log..."
echo "#######################################" >> ${DEBUG_LOG}
echo "############## Blacklist ##############" >> ${DEBUG_LOG}
echo "#######################################" >> ${DEBUG_LOG}
if [ -e "$BLACKLISTFILE" ]
then
cat "$BLACKLISTFILE" >> ${DEBUG_LOG}
echo >> ${DEBUG_LOG}
else
echo "No blacklist.txt file found!" >> ${DEBUG_LOG}
printf ":::\tNo blacklist.txt file found!\n"
fi
echo "::: Writing adlists.list to debug log..."
echo "#######################################" >> ${DEBUG_LOG}
echo "############ adlists.list #############" >> ${DEBUG_LOG}
echo "#######################################" >> ${DEBUG_LOG}
if [ -e "$ADLISTSFILE" ]
then
while read -r line; do
if [ ! -z "$line" ]; then
[[ "$line" =~ ^#.*$ ]] && continue
echo "$line" >> ${DEBUG_LOG}
fi
done < "$ADLISTSFILE"
echo >> ${DEBUG_LOG}
else
echo "No adlists.list file found... using adlists.default!" >> ${DEBUG_LOG}
printf ":::\tNo adlists.list file found... using adlists.default!\n"
fi
header_write "Analyzing gravity.list"
gravity_length=$(wc -l "${GRAVITYFILE}") \
&& log_write "${GRAVITYFILE} is ${gravity_length} lines long." \
|| log_echo "Warning: No gravity.list file found!"
# Continuously append the pihole.log file to the pihole_debug.log file # Continuously append the pihole.log file to the pihole_debug.log file
function dumpPiHoleLog { dumpPiHoleLog() {
trap '{ echo -e "\n::: Finishing debug write from interrupt... Quitting!" ; exit 1; }' INT trap '{ echo -e "\n::: Finishing debug write from interrupt... Quitting!" ; exit 1; }' INT
echo -e "::: Writing current Pi-hole traffic to debug log...\n:::\tTry loading any/all sites that you are having trouble with now... \n:::\t(Press ctrl+C to finish)" echo "::: "
echo "#######################################" >> ${DEBUG_LOG} echo "::: --= User Action Required =--"
echo "############# pihole.log ##############" >> ${DEBUG_LOG} echo -e "::: Try loading a site that you are having trouble with now from a client web browser.. \n:::\t(Press CTRL+C to finish logging.)"
echo "#######################################" >> ${DEBUG_LOG} header_write "pihole.log"
if [ -e "$PIHOLELOG" ] if [ -e "${PIHOLELOG}" ]; then
then
while true; do while true; do
tail -f "$PIHOLELOG" >> ${DEBUG_LOG} tail -f "${PIHOLELOG}" >> ${DEBUG_LOG}
echo >> ${DEBUG_LOG} log_write ""
done done
else else
echo "No pihole.log file found!" >> ${DEBUG_LOG} log_write "No pihole.log file found!"
printf ":::\tNo pihole.log file found!\n" printf ":::\tNo pihole.log file found!\n"
fi fi
} }
# Anything to be done after capturing of pihole.log terminates # Anything to be done after capturing of pihole.log terminates
function finalWork { finalWork() {
local tricorder
echo "::: Finshed debugging!" echo "::: Finshed debugging!"
echo "::: The debug log can be uploaded to Termbin.com for easier sharing." echo "::: The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only."
read -r -p "::: Would you like to upload the log? [y/N] " response read -r -p "::: Would you like to upload the log? [y/N] " response
case ${response} in case ${response} in
[yY][eE][sS]|[yY]) [yY][eE][sS]|[yY])
TERMBIN=$(cat /var/log/pihole_debug.log | nc termbin.com 9999) tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999)
;; ;;
*) *)
echo "::: Log will NOT be uploaded to Termbin." echo "::: Log will NOT be uploaded to tricorder."
;; ;;
esac esac
# Check if termbin.com is reachable. When it's not, point to local log instead # Check if tricorder.pi-hole.net is reachable and provide token.
if [ -n "$TERMBIN" ] if [ -n "${tricorder}" ]; then
then echo "::: Your debug token is : ${tricorder}"
echo "::: Debug log can be found at : $TERMBIN" echo "::: Please contact the Pi-hole team with your token to being assistance."
else echo "::: Thank you."
echo "::: Debug log can be found at : /var/log/pihole_debug.log"
fi fi
echo "::: Debug log can be found at : /var/log/pihole_debug.log"
} }
trap finalWork EXIT trap finalWork EXIT

@ -11,21 +11,6 @@
# (at your option) any later version. # (at your option) any later version.
############ FUNCTIONS ########### ############ FUNCTIONS ###########
# Run this script as root or under sudo
echo ":::"
if [[ $EUID -eq 0 ]];then
echo "::: You are root."
else
echo "::: sudo will be used."
# Check if it is actually installed
# If it isn't, exit because the install cannot complete
if [ -x "$(command -v sudo)" ];then
export SUDO="sudo"
else
echo "::: Please install sudo or run this script as root."
exit 1
fi
fi
# Borrowed from adafruit-pitft-helper < borrowed from raspi-config # Borrowed from adafruit-pitft-helper < borrowed from raspi-config
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L324-L334 # https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L324-L334
@ -45,11 +30,11 @@ getInitSys() {
autoLoginPiToConsole() { autoLoginPiToConsole() {
if [ -e /etc/init.d/lightdm ]; then if [ -e /etc/init.d/lightdm ]; then
if [ ${SYSTEMD} -eq 1 ]; then if [ ${SYSTEMD} -eq 1 ]; then
${SUDO} systemctl set-default multi-user.target systemctl set-default multi-user.target
${SUDO} ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
else else
${SUDO} update-rc.d lightdm disable 2 update-rc.d lightdm disable 2
${SUDO} sed /etc/inittab -i -e "s/1:2345:respawn:\/sbin\/getty --noclear 38400 tty1/1:2345:respawn:\/bin\/login -f pi tty1 <\/dev\/tty1 >\/dev\/tty1 2>&1/" sed /etc/inittab -i -e "s/1:2345:respawn:\/sbin\/getty --noclear 38400 tty1/1:2345:respawn:\/bin\/login -f pi tty1 <\/dev\/tty1 >\/dev\/tty1 2>&1/"
fi fi
fi fi
} }
@ -66,23 +51,23 @@ echo /usr/local/bin/chronometer.sh >> /home/pi/.bashrc
# Set up the LCD screen based on Adafruits instuctions: # Set up the LCD screen based on Adafruits instuctions:
# https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/easy-install # https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/easy-install
curl -SLs https://apt.adafruit.com/add-pin | ${SUDO} bash curl -SLs https://apt.adafruit.com/add-pin | bash
${SUDO} apt-get -y install raspberrypi-bootloader apt-get -y install raspberrypi-bootloader
${SUDO} apt-get -y install adafruit-pitft-helper apt-get -y install adafruit-pitft-helper
${SUDO} adafruit-pitft-helper -t 28r adafruit-pitft-helper -t 28r
# Download the cmdline.txt file that prevents the screen from going blank after a period of time # Download the cmdline.txt file that prevents the screen from going blank after a period of time
${SUDO} mv /boot/cmdline.txt /boot/cmdline.orig mv /boot/cmdline.txt /boot/cmdline.orig
${SUDO} curl -o /boot/cmdline.txt https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/cmdline.txt curl -o /boot/cmdline.txt https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/cmdline.txt
# Back up the original file and download the new one # Back up the original file and download the new one
${SUDO} mv /etc/default/console-setup /etc/default/console-setup.orig mv /etc/default/console-setup /etc/default/console-setup.orig
${SUDO} curl -o /etc/default/console-setup https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/console-setup curl -o /etc/default/console-setup https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/console-setup
# Instantly apply the font change to the LCD screen # Instantly apply the font change to the LCD screen
${SUDO} setupcon setupcon
${SUDO} reboot reboot
# Start showing the stats on the screen by running the command on another tty: # Start showing the stats on the screen by running the command on another tty:
# http://unix.stackexchange.com/questions/170063/start-a-process-on-a-different-tty # http://unix.stackexchange.com/questions/170063/start-a-process-on-a-different-tty

@ -0,0 +1,142 @@
#!/usr/bin/env bash
# Pi-hole: A black hole for Internet advertisements
# (c) 2015, 2016 by Jacob Salmela
# Network-wide ad blocking via your Raspberry Pi
# http://pi-hole.net
# Whitelists domains
#
# Pi-hole is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# Variables
webInterfaceGitUrl="https://github.com/pi-hole/AdminLTE.git"
webInterfaceDir="/var/www/html/admin"
piholeGitUrl="https://github.com/pi-hole/pi-hole.git"
piholeFilesDir="/etc/.pihole"
spinner() {
local pid=${1}
local delay=0.50
local spinstr='/-\|'
while [ "$(ps a | awk '{print $1}' | grep "${pid}")" ]; do
local temp=${spinstr#?}
printf " [%c] " "${spinstr}"
local spinstr=${temp}${spinstr%"$temp"}
sleep ${delay}
printf "\b\b\b\b\b\b"
done
printf " \b\b\b\b"
}
getGitFiles() {
# Setup git repos for directory and repository passed
# as arguments 1 and 2
echo ":::"
echo "::: Checking for existing repository..."
if is_repo "${1}"; then
update_repo "${1}"
else
make_repo "${1}" "${2}"
fi
}
is_repo() {
# Use git to check if directory is currently under VCS
echo -n "::: Checking $1 is a repo..."
cd "${1}" &> /dev/null || return 1
git status &> /dev/null && echo " OK!"; return 0 || echo " not found!"; return 1
}
make_repo() {
# Remove the non-repod interface and clone the interface
echo -n "::: Cloning $2 into $1..."
rm -rf "${1}"
git clone -q --depth 1 "${2}" "${1}" > /dev/null & spinner $!
echo " done!"
}
update_repo() {
# Pull the latest commits
echo -n "::: Updating repo in $1..."
cd "${1}" || exit 1
git stash -q > /dev/null & spinner $!
git pull -q > /dev/null & spinner $!
echo " done!"
}
if [ ! -d "/etc/.pihole" ]; then #This is unlikely
echo "::: Critical Error: Pi-Hole repo missing from system!"
echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole"
exit 1;
fi
if [ ! -d "/var/www/html/admin" ]; then #This is unlikely
echo "::: Critical Error: Pi-Hole repo missing from system!"
echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole"
exit 1;
fi
echo "::: Checking for updates..."
piholeVersion=$(pihole -v -p -c)
piholeVersionLatest=$(pihole -v -p -l)
webVersion=$(pihole -v -a -c)
webVersionLatest=$(pihole -v -a -l)
echo ":::"
echo "::: Pi-hole version is $piholeVersion (Latest version is $piholeVersionLatest)"
echo "::: Web Admin version is $webVersion (Latest version is $webVersionLatest)"
echo ":::"
# Logic
# If latest versions are blank - we've probably hit Github rate limit (stop running `pihole -up so often!):
# Update anyway
# If Core up to date AND web up to date:
# Do nothing
# If Core up to date AND web NOT up to date:
# Pull web repo
# If Core NOT up to date AND web up to date:
# pull pihole repo, run install --unattended -- reconfigure
# if Core NOT up to date AND web NOT up to date:
# pull pihole repo run install --unattended
if [[ ${piholeVersion} == ${piholeVersionLatest} && ${webVersion} == ${webVersionLatest} ]]; then
echo "::: Everything is up to date!"
echo ""
exit 0
elif [[ ${piholeVersion} == ${piholeVersionLatest} && ${webVersion} != ${webVersionLatest} ]]; then
echo "::: Pi-hole Web Admin files out of date"
getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl}
echo ":::"
webVersion=$(pihole -v -a -c)
echo "::: Web Admin version is now at ${webVersion}"
echo "::: If you had made any changes in '/var/www/html/admin', they have been stashed using 'git stash'"
echo ""
elif [[ ${piholeVersion} != ${piholeVersionLatest} && ${webVersion} == ${webVersionLatest} ]]; then
echo "::: Pi-hole core files out of date"
getGitFiles ${piholeFilesDir} ${piholeGitUrl}
/etc/.pihole/automated\ install/basic-install.sh --reconfigure --unattended
echo ":::"
piholeVersion=$(pihole -v -p -c)
echo "::: Pi-hole version is now at ${piholeVersion}"
echo "::: If you had made any changes in '/etc/.pihole', they have been stashed using 'git stash'"
echo ""
elif [[ ${piholeVersion} != ${piholeVersionLatest} && ${webVersion} != ${webVersionLatest} ]]; then
echo "::: Updating Everything"
getGitFiles ${piholeFilesDir} ${piholeGitUrl}
/etc/.pihole/automated\ install/basic-install.sh --unattended
webVersion=$(pihole -v -a -c)
piholeVersion=$(pihole -v -p -c)
echo ":::"
echo "::: Pi-hole version is now at ${piholeVersion}"
echo "::: If you had made any changes in '/etc/.pihole', they have been stashed using 'git stash'"
echo ":::"
echo "::: Pi-hole version is now at ${piholeVersion}"
echo "::: If you had made any changes in '/etc/.pihole', they have been stashed using 'git stash'"
echo ""
fi

@ -3,18 +3,98 @@
# (c) 2015, 2016 by Jacob Salmela # (c) 2015, 2016 by Jacob Salmela
# Network-wide ad blocking via your Raspberry Pi # Network-wide ad blocking via your Raspberry Pi
# http://pi-hole.net # http://pi-hole.net
# Whitelists domains # shows version numbers
# #
# Pi-hole is free software: you can redistribute it and/or modify # Pi-hole is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or # the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
piholeVersion=$(cd /etc/.pihole/ && git describe --tags --abbrev=0) # Flags:
webVersion=$(cd /var/www/html/admin/ && git describe --tags --abbrev=0) latest=false
current=false
piholeVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//') normalOutput() {
webVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//') piholeVersion=$(cd /etc/.pihole/ && git describe --tags --abbrev=0)
webVersion=$(cd /var/www/html/admin/ && git describe --tags --abbrev=0)
echo "::: Pi-hole version is $piholeVersion (Latest version is $piholeVersionLatest)" piholeVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//')
echo "::: Web-Admin version is $webVersion (Latest version is $webVersionLatest)" webVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//')
echo "::: Pi-hole version is ${piholeVersion} (Latest version is ${piholeVersionLatest})"
echo "::: Web-Admin version is ${webVersion} (Latest version is ${webVersionLatest})"
}
webOutput() {
for var in "$@"; do
case "${var}" in
"-l" | "--latest" ) latest=true;;
"-c" | "--current" ) current=true;;
* ) echo "::: Invalid Option!"; exit 1;
esac
done
if [[ "${latest}" == true && "${current}" == false ]]; then
webVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//')
echo ${webVersionLatest}
elif [[ "${latest}" == false && "${current}" == true ]]; then
webVersion=$(cd /var/www/html/admin/ && git describe --tags --abbrev=0)
echo ${webVersion}
else
webVersion=$(cd /var/www/html/admin/ && git describe --tags --abbrev=0)
webVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//')
echo "::: Web-Admin version is $webVersion (Latest version is $webVersionLatest)"
fi
}
coreOutput() {
for var in "$@"; do
case "${var}" in
"-l" | "--latest" ) latest=true;;
"-c" | "--current" ) current=true;;
* ) echo "::: Invalid Option!"; exit 1;
esac
done
if [[ "${latest}" == true && "${current}" == false ]]; then
piholeVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//')
echo ${piholeVersionLatest}
elif [[ "${latest}" == false && "${current}" == true ]]; then
piholeVersion=$(cd /etc/.pihole/ && git describe --tags --abbrev=0)
echo ${piholeVersion}
else
piholeVersion=$(cd /etc/.pihole/ && git describe --tags --abbrev=0)
piholeVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//')
echo "::: Pi-hole version is $piholeVersion (Latest version is $piholeVersionLatest)"
fi
}
helpFunc() {
cat << EOM
:::
::: Show Pi-hole/Web Admin versions
:::
::: Usage: pihole -v [ -a | -p ] [ -l | -c ]
:::
::: Options:
::: -a, --admin Show both current and latest versions of web admin
::: -p, --pihole Show both current and latest versions of Pi-hole core files
::: -l, --latest (Only after -a | -p) Return only latest version
::: -c, --current (Only after -a | -p) Return only current version
::: -h, --help Show this help dialog
:::
EOM
exit 1
}
if [[ $# = 0 ]]; then
normalOutput
fi
for var in "$@"; do
case "${var}" in
"-a" | "--admin" ) shift; webOutput "$@";;
"-p" | "--pihole" ) shift; coreOutput "$@" ;;
"-h" | "--help" ) helpFunc;;
esac
done

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

@ -1,10 +1,9 @@
_pihole() _pihole() {
{
local cur prev opts local cur prev opts
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="blacklist chronometer debug flush help query setupLCD uninstall updateDashboard updateGravity updatePihole version whitelist" opts="blacklist chronometer debug flush help query reconfigure setupLCD uninstall updateGravity updatePihole version whitelist"
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0 return 0

@ -12,6 +12,7 @@
server.modules = ( server.modules = (
"mod_access", "mod_access",
"mod_accesslog", "mod_accesslog",
"mod_auth",
"mod_expire", "mod_expire",
"mod_compress", "mod_compress",
"mod_redirect", "mod_redirect",
@ -52,10 +53,14 @@ $HTTP["url"] =~ "^/admin/" {
) )
} }
# Rewite js requests, must be out of $HTTP block due to bug #2526
url.rewrite = ( "^(?!/admin/).*\.js$" => "pihole/index.js" )
# If the URL does not start with /admin, then it is a query for an ad domain # If the URL does not start with /admin, then it is a query for an ad domain
$HTTP["url"] =~ "^(?!/admin)/.*" { $HTTP["url"] =~ "^(?!/admin)/.*" {
# Create a response header for debugging using curl -I # Create a response header for debugging using curl -I
setenv.add-response-header = ( "X-Pi-hole" => "A black hole for Internet advertisements." ) setenv.add-response-header = ( "X-Pi-hole" => "A black hole for Internet advertisements." )
# rewrite only js requests
url.rewrite = ("(.*).js" => "pihole/index.js")
} }
# Add user chosen options held in external file
include_shell "cat external.conf 2>/dev/null"

@ -11,6 +11,7 @@
server.modules = ( server.modules = (
"mod_access", "mod_access",
"mod_auth",
"mod_fastcgi", "mod_fastcgi",
"mod_accesslog", "mod_accesslog",
"mod_expire", "mod_expire",
@ -69,10 +70,14 @@ $HTTP["url"] =~ "^/admin/" {
setenv.add-response-header = ( "X-Pi-hole" => "The Pi-hole Web interface is working!" ) setenv.add-response-header = ( "X-Pi-hole" => "The Pi-hole Web interface is working!" )
} }
# Rewite js requests, must be out of $HTTP block due to bug #2526
url.rewrite = ( "^(?!/admin/).*\.js$" => "pihole/index.js" )
# If the URL does not start with /admin, then it is a query for an ad domain # If the URL does not start with /admin, then it is a query for an ad domain
$HTTP["url"] =~ "^(?!/admin)/.*" { $HTTP["url"] =~ "^(?!/admin)/.*" {
# Create a response header for debugging using curl -I # Create a response header for debugging using curl -I
setenv.add-response-header = ( "X-Pi-hole" => "A black hole for Internet advertisements." ) setenv.add-response-header = ( "X-Pi-hole" => "A black hole for Internet advertisements." )
# rewrite only js requests
url.rewrite = ("(.*).js" => "pihole/index.js")
} }
# Add user chosen options held in external file
include_shell "cat external.conf 2>/dev/null"

@ -8,6 +8,11 @@
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or # the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
#
# This file is under source-control of the Pi-hole installation and update
# scripts, any changes made to this file will be overwritten when the softare
# is updated or re-installed. Please make any changes to the appropriate crontab
# or other cron file snippets.
# Pi-hole: Update the ad sources once a week on Sunday at 01:59 # Pi-hole: Update the ad sources once a week on Sunday at 01:59
# Download any updates from the adlists # Download any updates from the adlists
@ -16,10 +21,6 @@
# Pi-hole: Update Pi-hole! Uncomment to enable auto update # Pi-hole: Update Pi-hole! Uncomment to enable auto update
#30 2 * * 7 root /usr/local/bin/pihole updatePihole #30 2 * * 7 root /usr/local/bin/pihole updatePihole
# Pi-hole: Parse the log file before it is flushed and save the stats to a database
# This will be used for a historical view of your Pi-hole's performance
#50 23 * * * root /usr/local/bin/dailyLog.sh # note: this is outdated
# Pi-hole: Flush the log daily at 00:00 so it doesn't get out of control # Pi-hole: Flush the log daily at 00:00 so it doesn't get out of control
# Stats will be viewable in the Web interface thanks to the cron job above # Stats will be viewable in the Web interface thanks to the cron job above
00 00 * * * root /usr/local/bin/pihole flush 00 00 * * * root /usr/local/bin/pihole flush

@ -32,18 +32,27 @@ useUpdateVars=false
IPv4_address="" IPv4_address=""
IPv6_address="" IPv6_address=""
# Find the rows and columns # Find the rows and columns will default to 80x24 is it can not be detected
rows=$(tput lines) screen_size=$(stty size 2>/dev/null || echo 24 80)
columns=$(tput cols) rows=$(echo $screen_size | awk '{print $1}')
columns=$(echo $screen_size | awk '{print $2}')
# Divide by two so the dialogs take up half of the screen, which looks nice. # Divide by two so the dialogs take up half of the screen, which looks nice.
r=$(( rows / 2 )) r=$(( rows / 2 ))
c=$(( columns / 2 )) c=$(( columns / 2 ))
# Unless the screen is tiny
r=$(( r < 20 ? 20 : r ))
c=$(( c < 70 ? 70 : c ))
######## Undocumented Flags. Shhh ########
skipSpaceCheck=false
reconfigure=false
runUnattended=false
######## FIRST CHECK ######## ######## FIRST CHECK ########
# Must be root to install # Must be root to install
echo ":::" echo ":::"
if [[ $EUID -eq 0 ]];then if [[ ${EUID} -eq 0 ]]; then
echo "::: You are root." echo "::: You are root."
else else
echo "::: Script called with non-root privileges. The Pi-hole installs server packages and configures" echo "::: Script called with non-root privileges. The Pi-hole installs server packages and configures"
@ -51,9 +60,10 @@ else
echo "::: any concerns with this requirement. Please be sure to download this script from a trusted source." echo "::: any concerns with this requirement. Please be sure to download this script from a trusted source."
echo ":::" echo ":::"
echo "::: Detecting the presence of the sudo utility for continuation of this install..." echo "::: Detecting the presence of the sudo utility for continuation of this install..."
if [ -x "$(command -v sudo)" ];then
if [ -x "$(command -v sudo)" ]; then
echo "::: Utility sudo located." echo "::: Utility sudo located."
exec sudo bash "$0" "$@" exec curl -sSL https://install.pi-hole.net | sudo bash "$@"
exit $? exit $?
else else
echo "::: sudo is needed for the Web interface to run pihole commands. Please run this script as root and it will be automatically installed." echo "::: sudo is needed for the Web interface to run pihole commands. Please run this script as root and it will be automatically installed."
@ -63,48 +73,56 @@ fi
# Compatibility # Compatibility
if [ -x "$(command -v apt-get)" ];then if [ -x "$(command -v apt-get)" ]; then
#Debian Family #Debian Family
#Decide if php should be `php5` or just `php` (Fixes issues with Ubuntu 16.04 LTS)
phpVer="php5"
apt-get install --dry-run php5 > /dev/null 2>&1 || phpVer="php"
############################################# #############################################
PKG_MANAGER="apt-get" PKG_MANAGER="apt-get"
PKG_CACHE="/var/lib/apt/lists/" PKG_CACHE="/var/lib/apt/lists/"
UPDATE_PKG_CACHE="$PKG_MANAGER update" UPDATE_PKG_CACHE="${PKG_MANAGER} update"
PKG_UPDATE="$PKG_MANAGER upgrade" PKG_UPDATE="${PKG_MANAGER} upgrade"
PKG_INSTALL="$PKG_MANAGER --yes --fix-missing install" PKG_INSTALL="${PKG_MANAGER} --yes --fix-missing install"
# grep -c will return 1 retVal on 0 matches, block this throwing the set -e with an OR TRUE # grep -c will return 1 retVal on 0 matches, block this throwing the set -e with an OR TRUE
PKG_COUNT="$PKG_MANAGER -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true" PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true"
# #########################################
# fixes for dependancy differences
# Debian 7 doesn't have iproute2 use iproute
${PKG_MANAGER} install --dry-run iproute2 > /dev/null 2>&1 && IPROUTE_PKG="iproute2" || IPROUTE_PKG="iproute"
# Ubuntu 16.04 LTS php / php5 fix
${PKG_MANAGER} install --dry-run php5 > /dev/null 2>&1 && phpVer="php5" || phpVer="php"
# #########################################
INSTALLER_DEPS=( apt-utils whiptail git dhcpcd5) INSTALLER_DEPS=( apt-utils whiptail git dhcpcd5)
PIHOLE_DEPS=( dnsutils bc dnsmasq lighttpd ${phpVer}-common ${phpVer}-cgi curl unzip wget sudo netcat cron iproute2 ) PIHOLE_DEPS=( dnsutils bc dnsmasq lighttpd ${phpVer}-common ${phpVer}-cgi curl unzip wget sudo netcat cron ${IPROUTE_PKG} )
LIGHTTPD_USER="www-data" LIGHTTPD_USER="www-data"
LIGHTTPD_GROUP="www-data" LIGHTTPD_GROUP="www-data"
LIGHTTPD_CFG="lighttpd.conf.debian" LIGHTTPD_CFG="lighttpd.conf.debian"
DNSMASQ_USER="dnsmasq" DNSMASQ_USER="dnsmasq"
package_check_install() { package_check_install() {
dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -c "ok installed" || ${PKG_INSTALL} "$1" dpkg-query -W -f='${Status}' "${1}" 2>/dev/null | grep -c "ok installed" || ${PKG_INSTALL} "${1}"
} }
elif [ -x "$(command -v rpm)" ];then elif [ -x "$(command -v rpm)" ]; then
# Fedora Family # Fedora Family
if [ -x "$(command -v dnf)" ];then if [ -x "$(command -v dnf)" ]; then
PKG_MANAGER="dnf" PKG_MANAGER="dnf"
else else
PKG_MANAGER="yum" PKG_MANAGER="yum"
fi fi
PKG_CACHE="/var/cache/$PKG_MANAGER" PKG_CACHE="/var/cache/${PKG_MANAGER}"
UPDATE_PKG_CACHE="$PKG_MANAGER check-update" UPDATE_PKG_CACHE="${PKG_MANAGER} check-update"
PKG_UPDATE="$PKG_MANAGER update -y" PKG_UPDATE="${PKG_MANAGER} update -y"
PKG_INSTALL="$PKG_MANAGER install -y" PKG_INSTALL="${PKG_MANAGER} install -y"
PKG_COUNT="$PKG_MANAGER check-update | grep -v ^Last | grep -c ^[a-zA-Z0-9]" PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l"
INSTALLER_DEPS=( iproute net-tools procps-ng newt git ) INSTALLER_DEPS=( iproute net-tools procps-ng newt git )
PIHOLE_DEPS=( epel-release bind-utils bc dnsmasq lighttpd lighttpd-fastcgi php-common php-cli php curl unzip wget findutils cronie sudo nmap-ncat ) PIHOLE_DEPS=( epel-release bind-utils bc dnsmasq lighttpd lighttpd-fastcgi php-common php-cli php curl unzip wget findutils cronie sudo nmap-ncat )
if grep -q 'Fedora' /etc/redhat-release; then
remove_deps=(epel-release);
PIHOLE_DEPS=( ${PIHOLE_DEPS[@]/$remove_deps} );
fi
LIGHTTPD_USER="lighttpd" LIGHTTPD_USER="lighttpd"
LIGHTTPD_GROUP="lighttpd" LIGHTTPD_GROUP="lighttpd"
LIGHTTPD_CFG="lighttpd.conf.fedora" LIGHTTPD_CFG="lighttpd.conf.fedora"
DNSMASQ_USER="nobody" DNSMASQ_USER="nobody"
package_check_install() { package_check_install() {
rpm -qa | grep ^"$1"- > /dev/null || ${PKG_INSTALL} "$1" rpm -qa | grep ^"${1}"- > /dev/null || ${PKG_INSTALL} "${1}"
} }
else else
echo "OS distribution not supported" echo "OS distribution not supported"
@ -112,14 +130,13 @@ else
fi fi
####### FUNCTIONS ########## ####### FUNCTIONS ##########
spinner() spinner() {
{
local pid=$1 local pid=$1
local delay=0.50 local delay=0.50
local spinstr='/-\|' local spinstr='/-\|'
while [ "$(ps a | awk '{print $1}' | grep "$pid")" ]; do while [ "$(ps a | awk '{print $1}' | grep "${pid}")" ]; do
local temp=${spinstr#?} local temp=${spinstr#?}
printf " [%c] " "$spinstr" printf " [%c] " "${spinstr}"
local spinstr=${temp}${spinstr%"$temp"} local spinstr=${temp}${spinstr%"$temp"}
sleep ${delay} sleep ${delay}
printf "\b\b\b\b\b\b" printf "\b\b\b\b\b\b"
@ -162,7 +179,7 @@ verifyFreeDiskSpace() {
local existing_free_kilobytes=$(df -Pk | grep -m1 '\/$' | awk '{print $4}') local existing_free_kilobytes=$(df -Pk | grep -m1 '\/$' | awk '{print $4}')
# - Unknown free disk space , not a integer # - Unknown free disk space , not a integer
if ! [[ "$existing_free_kilobytes" =~ ^([0-9])+$ ]]; then if ! [[ "${existing_free_kilobytes}" =~ ^([0-9])+$ ]]; then
echo "::: Unknown free disk space!" echo "::: Unknown free disk space!"
echo "::: We were unable to determine available free disk space on this system." echo "::: We were unable to determine available free disk space on this system."
echo "::: You may override this check and force the installation, however, it is not recommended" echo "::: You may override this check and force the installation, however, it is not recommended"
@ -173,7 +190,7 @@ verifyFreeDiskSpace() {
elif [[ ${existing_free_kilobytes} -lt ${required_free_kilobytes} ]]; then elif [[ ${existing_free_kilobytes} -lt ${required_free_kilobytes} ]]; then
echo "::: Insufficient Disk Space!" echo "::: Insufficient Disk Space!"
echo "::: Your system appears to be low on disk space. pi-hole recommends a minimum of $required_free_kilobytes KiloBytes." echo "::: Your system appears to be low on disk space. pi-hole recommends a minimum of $required_free_kilobytes KiloBytes."
echo "::: You only have $existing_free_kilobytes KiloBytes free." echo "::: You only have ${existing_free_kilobytes} KiloBytes free."
echo "::: If this is a new install you may need to expand your disk." echo "::: If this is a new install you may need to expand your disk."
echo "::: Try running 'sudo raspi-config', and choose the 'expand file system option'" echo "::: Try running 'sudo raspi-config', and choose the 'expand file system option'"
echo "::: After rebooting, run this installation again. (curl -L https://install.pi-hole.net | bash)" echo "::: After rebooting, run this installation again. (curl -L https://install.pi-hole.net | bash)"
@ -198,23 +215,21 @@ chooseInterface() {
# Loop sentinel variable # Loop sentinel variable
local firstLoop=1 local firstLoop=1
while read -r line while read -r line; do
do
mode="OFF" mode="OFF"
if [[ ${firstLoop} -eq 1 ]]; then if [[ ${firstLoop} -eq 1 ]]; then
firstLoop=0 firstLoop=0
mode="ON" mode="ON"
fi fi
interfacesArray+=("$line" "available" "$mode") interfacesArray+=("${line}" "available" "${mode}")
done <<< "$availableInterfaces" done <<< "${availableInterfaces}"
# Find out how many interfaces are available to choose from # Find out how many interfaces are available to choose from
interfaceCount=$(echo "$availableInterfaces" | wc -l) interfaceCount=$(echo "${availableInterfaces}" | wc -l)
chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to select)" ${r} ${c} ${interfaceCount}) chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to select)" ${r} ${c} ${interfaceCount})
chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty)
if [[ $? = 0 ]]; then if [[ $? = 0 ]]; then
for desiredInterface in ${chooseInterfaceOptions} for desiredInterface in ${chooseInterfaceOptions}; do
do
piholeInterface=${desiredInterface} piholeInterface=${desiredInterface}
echo "::: Using interface: $piholeInterface" echo "::: Using interface: $piholeInterface"
done done
@ -271,8 +286,8 @@ use4andor6() {
getStaticIPv4Settings() { getStaticIPv4Settings() {
# Ask if the user wants to use DHCP settings as their static IP # Ask if the user wants to use DHCP settings as their static IP
if (whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Do you want to use your current network settings as a static address? if (whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Do you want to use your current network settings as a static address?
IP address: $IPv4_address IP address: ${IPv4_address}
Gateway: $IPv4gw" ${r} ${c}); then Gateway: ${IPv4gw}" ${r} ${c}); then
# If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict. # If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict" "It is possible your router could still try to assign this IP to a device, which would cause a conflict. But in most cases the router is smart enough to not do that. whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict" "It is possible your router could still try to assign this IP to a device, which would cause a conflict. But in most cases the router is smart enough to not do that.
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want. If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
@ -282,20 +297,19 @@ It is also possible to use a DHCP reservation, but if you are going to do that,
# Otherwise, we need to ask the user to input their desired settings. # Otherwise, we need to ask the user to input their desired settings.
# Start by getting the IPv4 address (pre-filling it with info gathered from DHCP) # Start by getting the IPv4 address (pre-filling it with info gathered from DHCP)
# Start a loop to let the user enter their information with the chance to go back and edit it if necessary # Start a loop to let the user enter their information with the chance to go back and edit it if necessary
until [[ ${ipSettingsCorrect} = True ]] until [[ ${ipSettingsCorrect} = True ]]; do
do
# Ask for the IPv4 address # Ask for the IPv4 address
IPv4_address=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 address" --inputbox "Enter your desired IPv4 address" ${r} ${c} "$IPv4_address" 3>&1 1>&2 2>&3) IPv4_address=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 address" --inputbox "Enter your desired IPv4 address" ${r} ${c} "${IPv4_address}" 3>&1 1>&2 2>&3)
if [[ $? = 0 ]];then if [[ $? = 0 ]]; then
echo "::: Your static IPv4 address: $IPv4_address" echo "::: Your static IPv4 address: ${IPv4_address}"
# Ask for the gateway # Ask for the gateway
IPv4gw=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 gateway (router)" --inputbox "Enter your desired IPv4 default gateway" ${r} ${c} "$IPv4gw" 3>&1 1>&2 2>&3) IPv4gw=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 gateway (router)" --inputbox "Enter your desired IPv4 default gateway" ${r} ${c} "${IPv4gw}" 3>&1 1>&2 2>&3)
if [[ $? = 0 ]];then if [[ $? = 0 ]]; then
echo "::: Your static IPv4 gateway: $IPv4gw" echo "::: Your static IPv4 gateway: ${IPv4gw}"
# Give the user a chance to review their settings before moving on # Give the user a chance to review their settings before moving on
if (whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Are these settings correct? if (whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Are these settings correct?
IP address: $IPv4_address IP address: ${IPv4_address}
Gateway: $IPv4gw" ${r} ${c}); then Gateway: ${IPv4gw}" ${r} ${c}); then
# After that's done, the loop ends and we move on # After that's done, the loop ends and we move on
ipSettingsCorrect=True ipSettingsCorrect=True
else else
@ -321,37 +335,37 @@ It is also possible to use a DHCP reservation, but if you are going to do that,
setDHCPCD() { setDHCPCD() {
# Append these lines to dhcpcd.conf to enable a static IP # Append these lines to dhcpcd.conf to enable a static IP
echo "## interface $piholeInterface echo "## interface ${piholeInterface}
static ip_address=$IPv4_address static ip_address=${IPv4_address}
static routers=$IPv4gw static routers=${IPv4gw}
static domain_name_servers=$IPv4gw" | tee -a /etc/dhcpcd.conf >/dev/null static domain_name_servers=${IPv4gw}" | tee -a /etc/dhcpcd.conf >/dev/null
} }
setStaticIPv4() { setStaticIPv4() {
local IFCFG_FILE local IFCFG_FILE
local IPADDR local IPADDR
local CIDR local CIDR
if [[ -f /etc/dhcpcd.conf ]];then if [[ -f /etc/dhcpcd.conf ]]; then
# Debian Family # Debian Family
if grep -q "$IPv4_address" /etc/dhcpcd.conf; then if grep -q "${IPv4_address}" /etc/dhcpcd.conf; then
echo "::: Static IP already configured" echo "::: Static IP already configured"
else else
setDHCPCD setDHCPCD
ip addr replace dev "$piholeInterface" "$IPv4_address" ip addr replace dev "${piholeInterface}" "${IPv4_address}"
echo ":::" echo ":::"
echo "::: Setting IP to $IPv4_address. You may need to restart after the install is complete." echo "::: Setting IP to ${IPv4_address}. You may need to restart after the install is complete."
echo ":::" echo ":::"
fi fi
elif [[ -f /etc/sysconfig/network-scripts/ifcfg-${piholeInterface} ]];then elif [[ -f /etc/sysconfig/network-scripts/ifcfg-${piholeInterface} ]];then
# Fedora Family # Fedora Family
IFCFG_FILE=/etc/sysconfig/network-scripts/ifcfg-${piholeInterface} IFCFG_FILE=/etc/sysconfig/network-scripts/ifcfg-${piholeInterface}
if grep -q "$IPv4_address" "${IFCFG_FILE}"; then if grep -q "${IPv4_address}" "${IFCFG_FILE}"; then
echo "::: Static IP already configured" echo "::: Static IP already configured"
else else
IPADDR=$(echo "${IPv4_address}" | cut -f1 -d/) IPADDR=$(echo "${IPv4_address}" | cut -f1 -d/)
CIDR=$(echo "${IPv4_address}" | cut -f2 -d/) CIDR=$(echo "${IPv4_address}" | cut -f2 -d/)
# Backup existing interface configuration: # Backup existing interface configuration:
cp "${IFCFG_FILE}" "${IFCFG_FILE}".backup-"$(date +%Y-%m-%d-%H%M%S)" cp "${IFCFG_FILE}" "${IFCFG_FILE}".pihole.orig
# Build Interface configuration file: # Build Interface configuration file:
{ {
echo "# Configured via Pi-Hole installer" echo "# Configured via Pi-Hole installer"
@ -365,7 +379,7 @@ setStaticIPv4() {
echo "DNS2=$piholeDNS2" echo "DNS2=$piholeDNS2"
echo "USERCTL=no" echo "USERCTL=no"
}>> "${IFCFG_FILE}" }>> "${IFCFG_FILE}"
ip addr replace dev "$piholeInterface" "$IPv4_address" ip addr replace dev "${piholeInterface}" "${IPv4_address}"
if [ -x "$(command -v nmcli)" ];then if [ -x "$(command -v nmcli)" ];then
# Tell NetworkManager to read our new sysconfig file # Tell NetworkManager to read our new sysconfig file
nmcli con load "${IFCFG_FILE}" > /dev/null nmcli con load "${IFCFG_FILE}" > /dev/null
@ -380,9 +394,8 @@ setStaticIPv4() {
fi fi
} }
function valid_ip() valid_ip() {
{ local ip=${1}
local ip=$1
local stat=1 local stat=1
if [[ ${ip} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then if [[ ${ip} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
@ -397,7 +410,7 @@ function valid_ip()
return ${stat} return ${stat}
} }
setDNS(){ setDNS() {
DNSChooseCmd=(whiptail --separate-output --radiolist "Select Upstream DNS Provider. To use your own, select Custom." ${r} ${c} 6) DNSChooseCmd=(whiptail --separate-output --radiolist "Select Upstream DNS Provider. To use your own, select Custom." ${r} ${c} 6)
DNSChooseOptions=(Google "" on DNSChooseOptions=(Google "" on
OpenDNS "" off OpenDNS "" off
@ -434,45 +447,46 @@ setDNS(){
piholeDNS2="8.20.247.20" piholeDNS2="8.20.247.20"
;; ;;
Custom) Custom)
until [[ ${DNSSettingsCorrect} = True ]] until [[ ${DNSSettingsCorrect} = True ]]; do
do
strInvalid="Invalid" strInvalid="Invalid"
if [ ! ${piholeDNS1} ]; then if [ ! ${piholeDNS1} ]; then
if [ ! ${piholeDNS2} ]; then if [ ! ${piholeDNS2} ]; then
prePopulate="" prePopulate=""
else else
prePopulate=", $piholeDNS2" prePopulate=", ${piholeDNS2}"
fi fi
elif [ ${piholeDNS1} ] && [ ! ${piholeDNS2} ]; then elif [ ${piholeDNS1} ] && [ ! ${piholeDNS2} ]; then
prePopulate="$piholeDNS1" prePopulate="${piholeDNS1}"
elif [ ${piholeDNS1} ] && [ ${piholeDNS2} ]; then elif [ ${piholeDNS1} ] && [ ${piholeDNS2} ]; then
prePopulate="$piholeDNS1, $piholeDNS2" prePopulate="${piholeDNS1}, ${piholeDNS2}"
fi fi
piholeDNS=$(whiptail --backtitle "Specify Upstream DNS Provider(s)" --inputbox "Enter your desired upstream DNS provider(s), seperated by a comma.\n\nFor example '8.8.8.8, 8.8.4.4'" ${r} ${c} "$prePopulate" 3>&1 1>&2 2>&3)
if [[ $? = 0 ]];then piholeDNS=$(whiptail --backtitle "Specify Upstream DNS Provider(s)" --inputbox "Enter your desired upstream DNS provider(s), seperated by a comma.\n\nFor example '8.8.8.8, 8.8.4.4'" ${r} ${c} "${prePopulate}" 3>&1 1>&2 2>&3)
piholeDNS1=$(echo "$piholeDNS" | sed 's/[, \t]\+/,/g' | awk -F, '{print$1}')
piholeDNS2=$(echo "$piholeDNS" | sed 's/[, \t]\+/,/g' | awk -F, '{print$2}') if [[ $? = 0 ]]; then
if ! valid_ip "$piholeDNS1" || [ ! "$piholeDNS1" ]; then piholeDNS1=$(echo "${piholeDNS}" | sed 's/[, \t]\+/,/g' | awk -F, '{print$1}')
piholeDNS2=$(echo "${piholeDNS}" | sed 's/[, \t]\+/,/g' | awk -F, '{print$2}')
if ! valid_ip "${piholeDNS1}" || [ ! "${piholeDNS1}" ]; then
piholeDNS1=${strInvalid} piholeDNS1=${strInvalid}
fi fi
if ! valid_ip "$piholeDNS2" && [ "$piholeDNS2" ]; then if ! valid_ip "${piholeDNS2}" && [ "${piholeDNS2}" ]; then
piholeDNS2=${strInvalid} piholeDNS2=${strInvalid}
fi fi
else else
echo "::: Cancel selected, exiting...." echo "::: Cancel selected, exiting...."
exit 1 exit 1
fi fi
if [[ ${piholeDNS1} == "$strInvalid" ]] || [[ ${piholeDNS2} == "$strInvalid" ]]; then if [[ ${piholeDNS1} == "${strInvalid}" ]] || [[ ${piholeDNS2} == "${strInvalid}" ]]; then
whiptail --msgbox --backtitle "Invalid IP" --title "Invalid IP" "One or both entered IP addresses were invalid. Please try again.\n\n DNS Server 1: $piholeDNS1\n DNS Server 2: $piholeDNS2" ${r} ${c} whiptail --msgbox --backtitle "Invalid IP" --title "Invalid IP" "One or both entered IP addresses were invalid. Please try again.\n\n DNS Server 1: $piholeDNS1\n DNS Server 2: ${piholeDNS2}" ${r} ${c}
if [[ ${piholeDNS1} == "$strInvalid" ]]; then if [[ ${piholeDNS1} == "${strInvalid}" ]]; then
piholeDNS1="" piholeDNS1=""
fi fi
if [[ ${piholeDNS2} == "$strInvalid" ]]; then if [[ ${piholeDNS2} == "${strInvalid}" ]]; then
piholeDNS2="" piholeDNS2=""
fi fi
DNSSettingsCorrect=False DNSSettingsCorrect=False
else else
if (whiptail --backtitle "Specify Upstream DNS Provider(s)" --title "Upstream DNS Provider(s)" --yesno "Are these settings correct?\n DNS Server 1: $piholeDNS1\n DNS Server 2: $piholeDNS2" ${r} ${c}); then if (whiptail --backtitle "Specify Upstream DNS Provider(s)" --title "Upstream DNS Provider(s)" --yesno "Are these settings correct?\n DNS Server 1: $piholeDNS1\n DNS Server 2: ${piholeDNS2}" ${r} ${c}); then
DNSSettingsCorrect=True DNSSettingsCorrect=True
else else
# If the settings are wrong, the loop continues # If the settings are wrong, the loop continues
@ -488,7 +502,7 @@ setDNS(){
fi fi
} }
version_check_dnsmasq(){ version_check_dnsmasq() {
# Check if /etc/dnsmasq.conf is from pihole. If so replace with an original and install new in .d directory # Check if /etc/dnsmasq.conf is from pihole. If so replace with an original and install new in .d directory
local dnsmasq_conf="/etc/dnsmasq.conf" local dnsmasq_conf="/etc/dnsmasq.conf"
local dnsmasq_conf_orig="/etc/dnsmasq.conf.orig" local dnsmasq_conf_orig="/etc/dnsmasq.conf.orig"
@ -520,20 +534,51 @@ version_check_dnsmasq(){
cp ${dnsmasq_pihole_01_snippet} ${dnsmasq_pihole_01_location} cp ${dnsmasq_pihole_01_snippet} ${dnsmasq_pihole_01_location}
echo " done." echo " done."
sed -i "s/@INT@/$piholeInterface/" ${dnsmasq_pihole_01_location} sed -i "s/@INT@/$piholeInterface/" ${dnsmasq_pihole_01_location}
if [[ "$piholeDNS1" != "" ]]; then if [[ "${piholeDNS1}" != "" ]]; then
sed -i "s/@DNS1@/$piholeDNS1/" ${dnsmasq_pihole_01_location} sed -i "s/@DNS1@/$piholeDNS1/" ${dnsmasq_pihole_01_location}
else else
sed -i '/^server=@DNS1@/d' ${dnsmasq_pihole_01_location} sed -i '/^server=@DNS1@/d' ${dnsmasq_pihole_01_location}
fi fi
if [[ "$piholeDNS2" != "" ]]; then if [[ "${piholeDNS2}" != "" ]]; then
sed -i "s/@DNS2@/$piholeDNS2/" ${dnsmasq_pihole_01_location} sed -i "s/@DNS2@/$piholeDNS2/" ${dnsmasq_pihole_01_location}
else else
sed -i '/^server=@DNS2@/d' ${dnsmasq_pihole_01_location} sed -i '/^server=@DNS2@/d' ${dnsmasq_pihole_01_location}
fi fi
#sed -i "s/@HOSTNAME@/$hostname/" ${dnsmasq_pihole_01_location}
if [[ -f /etc/hostname ]]; then
hostname=$(</etc/hostname)
elif [ -x "$(command -v hostname)" ]; then
hostname=$(hostname -f)
fi
#Replace IPv4 and IPv6 tokens in 01-pihole.conf for pi.hole resolution.
if [[ "${IPv4_address}" != "" ]]; then
tmp=${IPv4_address%/*}
sed -i "s/@IPv4@/$tmp/" ${dnsmasq_pihole_01_location}
else
sed -i '/^address=\/pi.hole\/@IPv4@/d' ${dnsmasq_pihole_01_location}
sed -i '/^address=\/@HOSTNAME@\/@IPv4@/d' ${dnsmasq_pihole_01_location}
fi
if [[ "${IPv6_address}" != "" ]]; then
sed -i "s/@IPv6@/$IPv6_address/" ${dnsmasq_pihole_01_location}
else
sed -i '/^address=\/pi.hole\/@IPv6@/d' ${dnsmasq_pihole_01_location}
sed -i '/^address=\/@HOSTNAME@\/@IPv6@/d' ${dnsmasq_pihole_01_location}
fi
if [[ "${hostname}" != "" ]]; then
sed -i "s/@HOSTNAME@/$hostname/" ${dnsmasq_pihole_01_location}
else
sed -i '/^address=\/@HOSTNAME@*/d' ${dnsmasq_pihole_01_location}
fi
sed -i 's/^#conf-dir=\/etc\/dnsmasq.d$/conf-dir=\/etc\/dnsmasq.d/' ${dnsmasq_conf} sed -i 's/^#conf-dir=\/etc\/dnsmasq.d$/conf-dir=\/etc\/dnsmasq.d/' ${dnsmasq_conf}
} }
remove_legacy_scripts(){ remove_legacy_scripts() {
#Tidy up /usr/local/bin directory if installing over previous install. #Tidy up /usr/local/bin directory if installing over previous install.
oldFiles=( gravity chronometer whitelist blacklist piholeLogFlush updateDashboard uninstall setupLCD piholeDebug) oldFiles=( gravity chronometer whitelist blacklist piholeLogFlush updateDashboard uninstall setupLCD piholeDebug)
for i in "${oldFiles[@]}"; do for i in "${oldFiles[@]}"; do
@ -547,12 +592,15 @@ installScripts() {
# Install the scripts from /etc/.pihole to their various locations # Install the scripts from /etc/.pihole to their various locations
echo ":::" echo ":::"
echo -n "::: Installing scripts to /opt/pihole..." echo -n "::: Installing scripts to /opt/pihole..."
#clear out /opt/pihole and recreate it. This allows us to remove scripts from future installs
rm -rf /opt/pihole
install -o "${USER}" -m755 -d /opt/pihole install -o "${USER}" -m755 -d /opt/pihole
cd /etc/.pihole/ cd /etc/.pihole/
install -o "${USER}" -Dm755 -t /opt/pihole/ gravity.sh install -o "${USER}" -Dm755 -t /opt/pihole/ gravity.sh
install -o "${USER}" -Dm755 -t /opt/pihole/ ./advanced/Scripts/*.sh install -o "${USER}" -Dm755 -t /opt/pihole/ ./advanced/Scripts/*.sh
install -o "${USER}" -Dm755 -t /opt/pihole/ ./automated\ install/uninstall.sh
install -o "${USER}" -Dm755 -t /usr/local/bin/ pihole install -o "${USER}" -Dm755 -t /usr/local/bin/ pihole
install -Dm644 ./advanced/bash-completion/pihole /etc/bash_completion.d/pihole install -Dm644 ./advanced/bash-completion/pihole /etc/bash_completion.d/pihole
@ -566,7 +614,7 @@ installConfigs() {
version_check_dnsmasq version_check_dnsmasq
if [ ! -d "/etc/lighttpd" ]; then if [ ! -d "/etc/lighttpd" ]; then
mkdir /etc/lighttpd mkdir /etc/lighttpd
chown "$USER":root /etc/lighttpd chown "${USER}":root /etc/lighttpd
mv /etc/lighttpd/lighttpd.conf /etc/lighttpd/lighttpd.conf.orig mv /etc/lighttpd/lighttpd.conf /etc/lighttpd/lighttpd.conf.orig
fi fi
cp /etc/.pihole/advanced/${LIGHTTPD_CFG} /etc/lighttpd/lighttpd.conf cp /etc/.pihole/advanced/${LIGHTTPD_CFG} /etc/lighttpd/lighttpd.conf
@ -574,6 +622,8 @@ installConfigs() {
chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/run/lighttpd chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/run/lighttpd
mkdir -p /var/cache/lighttpd/compress mkdir -p /var/cache/lighttpd/compress
chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/compress chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/compress
mkdir -p /var/cache/lighttpd/uploads
chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/uploads
} }
stop_service() { stop_service() {
@ -621,36 +671,36 @@ update_pacakge_cache() {
#Check to see if apt-get update has already been run today #Check to see if apt-get update has already been run today
#it needs to have been run at least once on new installs! #it needs to have been run at least once on new installs!
timestamp=$(stat -c %Y ${PKG_CACHE}) timestamp=$(stat -c %Y ${PKG_CACHE})
timestampAsDate=$(date -d @"$timestamp" "+%b %e") timestampAsDate=$(date -d @"${timestamp}" "+%b %e")
today=$(date "+%b %e") today=$(date "+%b %e")
if [ ! "$today" == "$timestampAsDate" ]; then if [ ! "${today}" == "${timestampAsDate}" ]; then
#update package lists #update package lists
echo ":::" echo ":::"
echo -n "::: $PKG_MANAGER update has not been run today. Running now..." echo -n "::: ${PKG_MANAGER} update has not been run today. Running now..."
${UPDATE_PKG_CACHE} &> /dev/null & spinner $! ${UPDATE_PKG_CACHE} &> /dev/null & spinner $!
echo " done!" echo " done!"
fi fi
} }
notify_package_updates_available(){ notify_package_updates_available() {
# Let user know if they have outdated packages on their system and # Let user know if they have outdated packages on their system and
# advise them to run a package update at soonest possible. # advise them to run a package update at soonest possible.
echo ":::" echo ":::"
echo -n "::: Checking $PKG_MANAGER for upgraded packages...." echo -n "::: Checking ${PKG_MANAGER} for upgraded packages...."
updatesToInstall=$(eval "${PKG_COUNT}") updatesToInstall=$(eval "${PKG_COUNT}")
echo " done!" echo " done!"
echo ":::" echo ":::"
if [[ ${updatesToInstall} -eq "0" ]]; then if [[ ${updatesToInstall} -eq "0" ]]; then
echo "::: Your system is up to date! Continuing with Pi-hole installation..." echo "::: Your system is up to date! Continuing with Pi-hole installation..."
else else
echo "::: There are $updatesToInstall updates available for your system!" echo "::: There are ${updatesToInstall} updates available for your system!"
echo "::: We recommend you run '$PKG_UPDATE' after installing Pi-Hole! " echo "::: We recommend you run '${PKG_UPDATE}' after installing Pi-Hole! "
echo ":::" echo ":::"
fi fi
} }
install_dependent_packages(){ install_dependent_packages() {
# Install packages passed in via argument array # Install packages passed in via argument array
# No spinner - conflicts with set -e # No spinner - conflicts with set -e
declare -a argArray1=("${!1}") declare -a argArray1=("${!1}")
@ -693,6 +743,7 @@ update_repo() {
# Pull the latest commits # Pull the latest commits
echo -n "::: Updating repo in $1..." echo -n "::: Updating repo in $1..."
cd "${1}" || exit 1 cd "${1}" || exit 1
git stash -q > /dev/null & spinner $!
git pull -q > /dev/null & spinner $! git pull -q > /dev/null & spinner $!
echo " done!" echo " done!"
} }
@ -755,7 +806,7 @@ runGravity() {
/opt/pihole/gravity.sh /opt/pihole/gravity.sh
} }
create_pihole_user(){ create_pihole_user() {
# Check if user pihole exists and create if not # Check if user pihole exists and create if not
echo "::: Checking if user 'pihole' exists..." echo "::: Checking if user 'pihole' exists..."
id -u pihole &> /dev/null && echo "::: User 'pihole' already exists" || (echo "::: User 'pihole' doesn't exist. Creating..." && useradd -r -s /usr/sbin/nologin pihole) id -u pihole &> /dev/null && echo "::: User 'pihole' already exists" || (echo "::: User 'pihole' doesn't exist. Creating..." && useradd -r -s /usr/sbin/nologin pihole)
@ -778,7 +829,7 @@ configureFirewall() {
finalExports() { finalExports() {
#If it already exists, lets overwrite it with the new values. #If it already exists, lets overwrite it with the new values.
if [[ -f ${setupVars} ]];then if [[ -f ${setupVars} ]]; then
rm ${setupVars} rm ${setupVars}
fi fi
{ {
@ -790,7 +841,6 @@ finalExports() {
}>> "${setupVars}" }>> "${setupVars}"
} }
installPihole() { installPihole() {
# Install base files and web interface # Install base files and web interface
create_pihole_user create_pihole_user
@ -817,6 +867,11 @@ installPihole() {
} }
updatePihole() { updatePihole() {
# Refactoring of install script has changed the name of a couple of variables. Sort them out here.
sed -i 's/IPv4addr/IPv4_address/g' ${setupVars}
sed -i 's/piholeIPv6/IPv6_address/g' ${setupVars}
# Source ${setupVars} for use in the rest of the functions.
. ${setupVars}
# Install base files and web interface # Install base files and web interface
installScripts installScripts
installConfigs installConfigs
@ -834,9 +889,12 @@ configureSelinux() {
printf ":::\tChecking for SELinux policy development packages..." printf ":::\tChecking for SELinux policy development packages..."
package_check_install "selinux-policy-devel" > /dev/null package_check_install "selinux-policy-devel" > /dev/null
echo " installed!" echo " installed!"
printf "::: Enabling httpd server side includes (SSI).. " printf ":::\tEnabling httpd server side includes (SSI).. "
setsebool -P httpd_ssi_exec on &> /dev/null && echo "Success" || echo "SELinux not enabled" setsebool -P httpd_ssi_exec on &> /dev/null && echo "Success" || echo "SELinux not enabled"
printf "\n:::\tCompiling Pi-Hole SELinux policy..\n" printf "\n:::\tCompiling Pi-Hole SELinux policy..\n"
if ! [ -x "$(command -v systemctl)" ]; then
sed -i.bak '/systemd/d' /etc/.pihole/advanced/selinux/pihole.te
fi
checkmodule -M -m -o /etc/pihole/pihole.mod /etc/.pihole/advanced/selinux/pihole.te checkmodule -M -m -o /etc/pihole/pihole.mod /etc/.pihole/advanced/selinux/pihole.te
semodule_package -o /etc/pihole/pihole.pp -m /etc/pihole/pihole.mod semodule_package -o /etc/pihole/pihole.pp -m /etc/pihole/pihole.mod
semodule -i /etc/pihole/pihole.pp semodule -i /etc/pihole/pihole.pp
@ -850,7 +908,7 @@ displayFinalMessage() {
whiptail --msgbox --backtitle "Make it so." --title "Installation Complete!" "Configure your devices to use the Pi-hole as their DNS server using: whiptail --msgbox --backtitle "Make it so." --title "Installation Complete!" "Configure your devices to use the Pi-hole as their DNS server using:
IPv4: ${IPv4_address%/*} IPv4: ${IPv4_address%/*}
IPv6: $IPv6_address IPv6: ${IPv6_address}
If you set a new IP address, you should restart the Pi. If you set a new IP address, you should restart the Pi.
@ -858,21 +916,32 @@ The install log is in /etc/pihole.
View the web interface at http://pi.hole/admin or http://${IPv4_address%/*}/admin" ${r} ${c} View the web interface at http://pi.hole/admin or http://${IPv4_address%/*}/admin" ${r} ${c}
} }
update_dialogs(){ update_dialogs() {
# reconfigure
if [ "${reconfigure}" = true ]; then
opt1a="Repair"
opt1b="This will retain existing settings"
strAdd="You will remain on the same version"
else
opt1a="Update"
opt1b="This will retain existing settings."
strAdd="You will be updated to the latest version."
fi
opt2a="Reconfigure"
opt2b="This will allow you to enter new settings"
UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\n\nWe have detected an existing install.\n\nPlease choose from the following options:" ${r} ${c} 2 \ UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\n\nWe have detected an existing install.\n\nPlease choose from the following options: \n($strAdd)" ${r} ${c} 2 \
"Update" "Update install will retain existing settings." \ "${opt1a}" "${opt1b}" \
"Install" "Install will allow you to enter new settings." 3>&2 2>&1 1>&3) "${opt2a}" "${opt2b}" 3>&2 2>&1 1>&3)
if [[ $? = 0 ]];then if [[ $? = 0 ]];then
case ${UpdateCmd} in case ${UpdateCmd} in
Update) ${opt1a})
echo "::: Updating existing install" echo "::: ${opt1a} option selected."
. ${setupVars}
useUpdateVars=true useUpdateVars=true
;; ;;
Install) ${opt2a})
echo "::: Running complete install script" echo "::: ${opt2a} option selected"
useUpdateVars=false useUpdateVars=false
;; ;;
esac esac
@ -884,45 +953,59 @@ update_dialogs(){
} }
main() { main() {
if [[ -f ${setupVars} ]];then # Check arguments for the undocumented flags
if [ "$1" == "pihole" ]; then for var in "$@"; do
case "$var" in
"--reconfigure" ) reconfigure=true;;
"--i_do_not_follow_recommendations" ) skipSpaceCheck=false;;
"--unattended" ) runUnattended=true;;
esac
done
if [[ -f ${setupVars} ]]; then
if [[ "${runUnattended}" == true ]]; then
echo "::: --unattended passed to install script, no whiptail dialogs will be displayed"
useUpdateVars=true useUpdateVars=true
else else
update_dialogs update_dialogs
fi fi
fi fi
# Start the installer # Start the installer
# Verify there is enough disk space for the install # Verify there is enough disk space for the install
if [[ $1 = "--i_do_not_follow_recommendations" ]]; then if [[ "${skipSpaceCheck}" == true ]]; then
echo "::: --i_do_not_follow_recommendations passed to script" echo "::: --i_do_not_follow_recommendations passed to script, skipping free disk space verification!"
echo "::: skipping free disk space verification!" else
else
verifyFreeDiskSpace verifyFreeDiskSpace
fi fi
# Update package cache
update_pacakge_cache
# Update package cache # Notify user of package availability
update_pacakge_cache notify_package_updates_available
# Notify user of package availability # Install packages used by this installation script
notify_package_updates_available install_dependent_packages INSTALLER_DEPS[@]
# Install packages used by this installation script # Install packages used by the Pi-hole
install_dependent_packages INSTALLER_DEPS[@] install_dependent_packages PIHOLE_DEPS[@]
# Install packages used by the Pi-hole if [[ "${reconfigure}" == true ]]; then
install_dependent_packages PIHOLE_DEPS[@] echo "::: --reconfigure passed to install script. Not downloading/updating local repos"
else
# Get Git files for Core and Admin
getGitFiles ${piholeFilesDir} ${piholeGitUrl}
getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl}
fi
if [[ ${useUpdateVars} == false ]]; then if [[ ${useUpdateVars} == false ]]; then
# Display welcome dialogs # Display welcome dialogs
welcomeDialogs welcomeDialogs
# Create directory for Pi-hole storage # Create directory for Pi-hole storage
mkdir -p /etc/pihole/ mkdir -p /etc/pihole/
# Remove legacy scripts from previous storage location # Remove legacy scripts from previous storage location
remove_legacy_scripts remove_legacy_scripts
# Get Git files for Core and Admin
getGitFiles ${piholeFilesDir} ${piholeGitUrl}
getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl}
# Stop resolver and webserver while installing proceses # Stop resolver and webserver while installing proceses
stop_service dnsmasq stop_service dnsmasq
stop_service lighttpd stop_service lighttpd
@ -936,39 +1019,39 @@ if [[ ${useUpdateVars} == false ]]; then
setDNS setDNS
# Install and log everything to a file # Install and log everything to a file
installPihole | tee ${tmpLog} installPihole | tee ${tmpLog}
else else
updatePihole | tee ${tmpLog} updatePihole | tee ${tmpLog}
fi fi
# Move the log file into /etc/pihole for storage # Move the log file into /etc/pihole for storage
mv ${tmpLog} ${instalLogLoc} mv ${tmpLog} ${instalLogLoc}
if [[ ${useUpdateVars} == false ]]; then if [[ "${useUpdateVars}" == false ]]; then
displayFinalMessage displayFinalMessage
fi fi
echo -n "::: Restarting services..." echo "::: Restarting services..."
# Start services # Start services
start_service dnsmasq start_service dnsmasq
enable_service dnsmasq enable_service dnsmasq
start_service lighttpd start_service lighttpd
enable_service lighttpd enable_service lighttpd
echo " done." echo "::: done."
echo ":::" echo ":::"
if [[ ${useUpdateVars} == false ]]; then if [[ "${useUpdateVars}" == false ]]; then
echo "::: Installation Complete! Configure your devices to use the Pi-hole as their DNS server using:" echo "::: Installation Complete! Configure your devices to use the Pi-hole as their DNS server using:"
echo "::: ${IPv4_address%/*}" echo "::: ${IPv4_address%/*}"
echo "::: $IPv6_address" echo "::: ${IPv6_address}"
echo ":::" echo ":::"
echo "::: If you set a new IP address, you should restart the Pi." echo "::: If you set a new IP address, you should restart the Pi."
else else
echo "::: Update complete!" echo "::: Update complete!"
fi fi
echo ":::" echo ":::"
echo "::: The install log is located at: /etc/pihole/install.log" echo "::: The install log is located at: /etc/pihole/install.log"
echo "::: View the web interface at http://pi.hole/admin or http://${IPv4_address%/*}/admin" echo "::: View the web interface at http://pi.hole/admin or http://${IPv4_address%/*}/admin"
} }
if [[ -z "$PHTEST" ]] ; then if [[ -z "$PHTEST" ]] ; then

@ -11,13 +11,13 @@
# (at your option) any later version. # (at your option) any later version.
# Must be root to uninstall # Must be root to uninstall
if [[ $EUID -eq 0 ]];then if [[ ${EUID} -eq 0 ]]; then
echo "::: You are root." echo "::: You are root."
else else
echo "::: Sudo will be used for the uninstall." echo "::: Sudo will be used for the uninstall."
# Check if it is actually installed # Check if it is actually installed
# If it isn't, exit because the unnstall cannot complete # If it isn't, exit because the unnstall cannot complete
if [ -x "$(command -v sudo)" ];then if [ -x "$(command -v sudo)" ]; then
export SUDO="sudo" export SUDO="sudo"
else else
echo "::: Please install sudo or run this as root." echo "::: Please install sudo or run this as root."
@ -26,14 +26,14 @@ else
fi fi
# Compatability # Compatability
if [ -x "$(command -v rpm)" ];then if [ -x "$(command -v rpm)" ]; then
# Fedora Family # Fedora Family
if [ -x "$(command -v dnf)" ];then if [ -x "$(command -v dnf)" ]; then
PKG_MANAGER="dnf" PKG_MANAGER="dnf"
else else
PKG_MANAGER="yum" PKG_MANAGER="yum"
fi fi
PKG_REMOVE="$PKG_MANAGER remove -y" PKG_REMOVE="${PKG_MANAGER} remove -y"
PIHOLE_DEPS=( bind-utils bc dnsmasq lighttpd lighttpd-fastcgi php-common git curl unzip wget findutils ) PIHOLE_DEPS=( bind-utils bc dnsmasq lighttpd lighttpd-fastcgi php-common git curl unzip wget findutils )
package_check() { package_check() {
rpm -qa | grep ^$1- > /dev/null rpm -qa | grep ^$1- > /dev/null
@ -41,10 +41,10 @@ if [ -x "$(command -v rpm)" ];then
package_cleanup() { package_cleanup() {
${SUDO} ${PKG_MANAGER} -y autoremove ${SUDO} ${PKG_MANAGER} -y autoremove
} }
elif [ -x "$(command -v apt-get)" ];then elif [ -x "$(command -v apt-get)" ]; then
# Debian Family # Debian Family
PKG_MANAGER="apt-get" PKG_MANAGER="apt-get"
PKG_REMOVE="$PKG_MANAGER -y remove --purge" PKG_REMOVE="${PKG_MANAGER} -y remove --purge"
PIHOLE_DEPS=( dnsutils bc dnsmasq lighttpd php5-common git curl unzip wget ) PIHOLE_DEPS=( dnsutils bc dnsmasq lighttpd php5-common git curl unzip wget )
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"
@ -58,37 +58,36 @@ else
exit exit
fi fi
spinner() spinner() {
{
local pid=$1 local pid=$1
local delay=0.50 local delay=0.50
local spinstr='/-\|' local spinstr='/-\|'
while [ "$(ps a | awk '{print $1}' | grep "$pid")" ]; do while [ "$(ps a | awk '{print $1}' | grep "${pid}")" ]; do
local temp=${spinstr#?} local temp=${spinstr#?}
printf " [%c] " "$spinstr" printf " [%c] " "${spinstr}"
local spinstr=${temp}${spinstr%"$temp"} local spinstr=${temp}${spinstr%"$temp}"}
sleep ${delay} sleep ${delay}
printf "\b\b\b\b\b\b" printf "\b\b\b\b\b\b"
done done
printf " \b\b\b\b" printf " \b\b\b\b"
} }
function removeAndPurge { removeAndPurge() {
# Purge dependencies # Purge dependencies
echo ":::" echo ":::"
for i in "${PIHOLE_DEPS[@]}"; do for i in "${PIHOLE_DEPS[@]}"; do
package_check ${i} > /dev/null package_check ${i} > /dev/null
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
while true; do while true; do
read -rp "::: Do you wish to remove $i from your system? [y/n]: " yn read -rp "::: Do you wish to remove ${i} from your system? [y/n]: " yn
case ${yn} in case ${yn} in
[Yy]* ) printf ":::\tRemoving %s..." "$i"; ${SUDO} ${PKG_REMOVE} "$i" &> /dev/null & spinner $!; printf "done!\n"; break;; [Yy]* ) printf ":::\tRemoving %s..." "${i}"; ${SUDO} ${PKG_REMOVE} "${i}" &> /dev/null & spinner $!; printf "done!\n"; break;;
[Nn]* ) printf ":::\tSkipping %s" "$i\n"; break;; [Nn]* ) printf ":::\tSkipping %s" "${i}\n"; break;;
* ) printf "::: You must answer yes or no!\n";; * ) printf "::: You must answer yes or no!\n";;
esac esac
done done
else else
printf ":::\tPackage %s not installed... Not removing.\n" "$i" printf ":::\tPackage %s not installed... Not removing.\n" "${i}"
fi fi
done done
@ -104,7 +103,7 @@ echo ":::"
removeNoPurge removeNoPurge
} }
function removeNoPurge { removeNoPurge() {
echo ":::" echo ":::"
# Only web directories/files that are created by pihole should be removed. # Only web directories/files that are created by pihole should be removed.
echo "::: Removing the Pi-hole Web server files..." echo "::: Removing the Pi-hole Web server files..."

@ -13,42 +13,38 @@
# Run this script as root or under sudo # Run this script as root or under sudo
echo ":::" echo ":::"
if [[ $EUID -eq 0 ]];then helpFunc() {
echo "::: You are root." cat << EOM
else ::: Pull in domains from adlists
echo "::: sudo will be used." :::
# Check if it is actually installed ::: Usage: pihole -g
# If it isn't, exit because the install cannot complete :::
if [ -x "$(command -v sudo)" ];then ::: Options:
export SUDO="sudo" ::: -f, --force Force lists to be downloaded, even if they don't need updating.
else ::: -h, --help Show this help dialog
echo "::: Please install sudo or run this script as root." EOM
exit 1
fi
fi
function helpFunc()
{
echo "::: Pull in domains from adlists"
echo ":::"
echo "::: Usage: pihole -g"
echo ":::"
echo "::: Options:"
echo "::: -f, --force Force lists to be downloaded, even if they don't need updating."
echo "::: -h, --help Show this help dialog"
exit 1 exit 1
} }
adListFile=/etc/pihole/adlists.list adListFile=/etc/pihole/adlists.list
adListDefault=/etc/pihole/adlists.default adListDefault=/etc/pihole/adlists.default
whitelistScript=/opt/pihole/whitelist.sh whitelistScript="pihole -w"
blacklistScript=/opt/pihole/blacklist.sh whitelistFile=/etc/pihole/whitelist.txt
blacklistFile=/etc/pihole/blacklist.txt
#Source the setupVars from install script for the IP #Source the setupVars from install script for the IP
. /etc/pihole/setupVars.conf setupVars=/etc/pihole/setupVars.conf
if [[ -f ${setupVars} ]];then
. /etc/pihole/setupVars.conf
else
echo "::: WARNING: /etc/pihole/setupVars.conf missing. Possible installation failure."
echo "::: Please run 'pihole -r', and choose the 'reconfigure' option to reconfigure."
exit 1
fi
#Remove the /* from the end of the IPv4addr. #Remove the /* from the end of the IPv4addr.
IPv4addr=${IPv4_address%/*} IPv4_address=${IPv4_address%/*}
# Variables for various stages of downloading and formatting the list # Variables for various stages of downloading and formatting the list
basename=pihole basename=pihole
@ -57,18 +53,20 @@ adList=${piholeDir}/gravity.list
justDomainsExtension=domains justDomainsExtension=domains
matterAndLight=${basename}.0.matterandlight.txt matterAndLight=${basename}.0.matterandlight.txt
supernova=${basename}.1.supernova.txt supernova=${basename}.1.supernova.txt
eventHorizon=${basename}.2.eventHorizon.txt preEventHorizon=list.preEventHorizon
eventHorizon=${basename}.2.supernova.txt
accretionDisc=${basename}.3.accretionDisc.txt accretionDisc=${basename}.3.accretionDisc.txt
# After setting defaults, check if there's local overrides skipDownload=false
if [[ -r ${piholeDir}/pihole.conf ]];then
echo "::: Local calibration requested..." # Warn users still using pihole.conf that it no longer has any effect (I imagine about 2 people use it)
. ${piholeDir}/pihole.conf if [[ -r ${piholeDir}/pihole.conf ]]; then
echo "::: pihole.conf file no longer supported. Over-rides in this file are ignored."
fi fi
########################### ###########################
# collapse - begin formation of pihole # collapse - begin formation of pihole
function gravity_collapse() { gravity_collapse() {
echo "::: Neutrino emissions detected..." echo "::: Neutrino emissions detected..."
echo ":::" echo ":::"
#Decide if we're using a custom ad block list, or defaults. #Decide if we're using a custom ad block list, or defaults.
@ -99,31 +97,17 @@ function gravity_collapse() {
done < ${adListDefault} done < ${adListDefault}
echo " done!" echo " done!"
fi fi
# Create the pihole resource directory if it doesn't exist. Future files will be stored here
if [[ -d ${piholeDir} ]];then
# Temporary hack to allow non-root access to pihole directory
# Will update later, needed for existing installs, new installs should
# create this directory as non-root
${SUDO} chmod 777 ${piholeDir}
echo ":::"
echo "::: Existing pihole directory found"
else
echo "::: Creating pihole directory..."
mkdir ${piholeDir}
${SUDO} chmod 777 ${piholeDir}
fi
} }
# patternCheck - check to see if curl downloaded any new files. # patternCheck - check to see if curl downloaded any new files.
function gravity_patternCheck() { gravity_patternCheck() {
patternBuffer=$1 patternBuffer=$1
# check if the patternbuffer is a non-zero length file # check if the patternbuffer is a non-zero length file
if [[ -s "$patternBuffer" ]];then if [[ -s "${patternBuffer}" ]]; then
# Some of the blocklists are copyright, they need to be downloaded # Some of the blocklists are copyright, they need to be downloaded
# and stored as is. They can be processed for content after they # and stored as is. They can be processed for content after they
# have been saved. # have been saved.
cp "$patternBuffer" "$saveLocation" mv "${patternBuffer}" "${saveLocation}"
echo " List updated, transport successful!" echo " List updated, transport successful!"
else else
# curl didn't download any host files, probably because of the date check # curl didn't download any host files, probably because of the date check
@ -132,7 +116,7 @@ function gravity_patternCheck() {
} }
# transport - curl the specified url with any needed command extentions # transport - curl the specified url with any needed command extentions
function gravity_transport() { gravity_transport() {
url=$1 url=$1
cmd_ext=$2 cmd_ext=$2
agent=$3 agent=$3
@ -142,26 +126,23 @@ function gravity_transport() {
heisenbergCompensator="" heisenbergCompensator=""
if [[ -r ${saveLocation} ]]; then if [[ -r ${saveLocation} ]]; then
# if domain has been saved, add file for date check to only download newer # if domain has been saved, add file for date check to only download newer
heisenbergCompensator="-z $saveLocation" heisenbergCompensator="-z ${saveLocation}"
fi fi
# Silently curl url # Silently curl url
curl -s -L ${cmd_ext} ${heisenbergCompensator} -A "$agent" ${url} > ${patternBuffer} curl -s -L ${cmd_ext} ${heisenbergCompensator} -A "${agent}" ${url} > ${patternBuffer}
# Check for list updates # Check for list updates
gravity_patternCheck "$patternBuffer" gravity_patternCheck "${patternBuffer}"
# Cleanup
rm -f "$patternBuffer"
} }
# spinup - main gravity function # spinup - main gravity function
function gravity_spinup() { gravity_spinup() {
echo ":::" echo ":::"
# Loop through domain list. Download each one and remove commented lines (lines beginning with '# 'or '/') and # blank lines # Loop through domain list. Download each one and remove commented lines (lines beginning with '# 'or '/') and # blank lines
for ((i = 0; i < "${#sources[@]}"; i++)) for ((i = 0; i < "${#sources[@]}"; i++)); do
do
url=${sources[$i]} url=${sources[$i]}
# Get just the domain from the URL # Get just the domain from the URL
domain=$(echo "$url" | cut -d'/' -f3) domain=$(echo "${url}" | cut -d'/' -f3)
# Save the file as list.#.domain # Save the file as list.#.domain
saveLocation=${piholeDir}/list.${i}.${domain}.${justDomainsExtension} saveLocation=${piholeDir}/list.${i}.${domain}.${justDomainsExtension}
@ -169,11 +150,9 @@ function gravity_spinup() {
agent="Mozilla/10.0" agent="Mozilla/10.0"
echo -n "::: Getting $domain list..."
# Use a case statement to download lists that need special cURL commands # Use a case statement to download lists that need special cURL commands
# to complete properly and reset the user agent when required # to complete properly and reset the user agent when required
case "$domain" in case "${domain}" in
"adblock.mahakala.is") "adblock.mahakala.is")
agent='Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36' agent='Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'
cmd_ext="-e http://forum.xda-developers.com/" cmd_ext="-e http://forum.xda-developers.com/"
@ -186,83 +165,101 @@ function gravity_spinup() {
# Default is a simple request # Default is a simple request
*) cmd_ext="" *) cmd_ext=""
esac esac
if [[ "${skipDownload}" == false ]]; then
echo -n "::: Getting $domain list..."
gravity_transport "$url" "$cmd_ext" "$agent" gravity_transport "$url" "$cmd_ext" "$agent"
fi
done done
} }
# Schwarzchild - aggregate domains to one list and add blacklisted domains # Schwarzchild - aggregate domains to one list and add blacklisted domains
function gravity_Schwarzchild() { gravity_Schwarzchild() {
echo "::: " echo "::: "
# Find all active domains and compile them into one file and remove CRs # Find all active domains and compile them into one file and remove CRs
echo -n "::: Aggregating list of domains..." echo -n "::: Aggregating list of domains..."
truncate -s 0 ${piholeDir}/${matterAndLight} truncate -s 0 ${piholeDir}/${matterAndLight}
for i in "${activeDomains[@]}" for i in "${activeDomains[@]}"; do
do cat "${i}" | tr -d '\r' >> ${piholeDir}/${matterAndLight}
cat "$i" | tr -d '\r' >> ${piholeDir}/${matterAndLight}
done done
echo " done!" echo " done!"
} }
function gravity_Blacklist(){ gravity_Blacklist() {
# Append blacklist entries if they exist # Append blacklist entries to eventHorizon if they exist
echo -n "::: Running blacklist script to update HOSTS file...." if [[ -f "${blacklistFile}" ]]; then
${blacklistScript} -f -nr -q > /dev/null numBlacklisted=$(wc -l < "${blacklistFile}")
numBlacklisted=$(wc -l < "/etc/pihole/blacklist.txt")
plural=; [[ "$numBlacklisted" != "1" ]] && plural=s plural=; [[ "$numBlacklisted" != "1" ]] && plural=s
echo " $numBlacklisted domain${plural} blacklisted!" echo -n "::: BlackListing $numBlacklisted domain${plural}..."
cat ${blacklistFile} >> ${piholeDir}/${eventHorizon}
echo " done!"
else
echo "::: Nothing to blacklist!"
fi
} }
function gravity_Whitelist() { gravity_Whitelist() {
#${piholeDir}/${eventHorizon})
echo ":::" echo ":::"
# Prevent our sources from being pulled into the hole # Prevent our sources from being pulled into the hole
plural=; [[ "${sources[@]}" != "1" ]] && plural=s plural=; [[ "${sources[@]}" != "1" ]] && plural=s
echo -n "::: Adding ${#sources[@]} adlist source${plural} to the whitelist..." echo -n "::: Adding adlist source${plural} to the whitelist..."
urls=() urls=()
for url in "${sources[@]}" for url in "${sources[@]}"; do
do tmp=$(echo "${url}" | awk -F '/' '{print $3}')
tmp=$(echo "$url" | awk -F '/' '{print $3}')
urls=("${urls[@]}" ${tmp}) urls=("${urls[@]}" ${tmp})
done done
echo " done!" echo " done!"
echo -n "::: Running whitelist script to update HOSTS file...." # Ensure adlist domains are in whitelist.txt
${whitelistScript} -f -nr -q "${urls[@]}" > /dev/null ${whitelistScript} -nr -q "${urls[@]}" > /dev/null
numWhitelisted=$(wc -l < "/etc/pihole/whitelist.txt")
# Check whitelist.txt exists.
if [[ -f "${whitelistFile}" ]]; then
# Remove anything in whitelist.txt from the Event Horizon
numWhitelisted=$(wc -l < "${whitelistFile}")
plural=; [[ "$numWhitelisted" != "1" ]] && plural=s plural=; [[ "$numWhitelisted" != "1" ]] && plural=s
echo " $numWhitelisted domain${plural} whitelisted!" echo -n "::: Whitelisting $numWhitelisted domain${plural}..."
#print everything from preEventHorizon into eventHorizon EXCEPT domains in whitelist.txt
grep -F -x -v -f ${whitelistFile} ${piholeDir}/${preEventHorizon} > ${piholeDir}/${eventHorizon}
echo " done!"
else
echo "::: Nothing to whitelist!"
fi
} }
function gravity_unique() { gravity_unique() {
# Sort and remove duplicates # Sort and remove duplicates
echo -n "::: Removing duplicate domains...." echo -n "::: Removing duplicate domains...."
sort -u ${piholeDir}/${supernova} > ${piholeDir}/${eventHorizon} sort -u ${piholeDir}/${supernova} > ${piholeDir}/${preEventHorizon}
echo " done!" echo " done!"
numberOf=$(wc -l < ${piholeDir}/${eventHorizon}) numberOf=$(wc -l < ${piholeDir}/${preEventHorizon})
echo "::: $numberOf unique domains trapped in the event horizon." echo "::: $numberOf unique domains trapped in the event horizon."
} }
function gravity_hostFormat() { gravity_hostFormat() {
# Format domain list as "192.168.x.x domain.com" # Format domain list as "192.168.x.x domain.com"
echo "::: Formatting domains into a HOSTS file..." echo "::: Formatting domains into a HOSTS file..."
if [[ -f /etc/hostname ]]; then # Check vars from setupVars.conf to see if we're using IPv4, IPv6, Or both.
hostname=$(</etc/hostname) if [[ -n "${IPv4_address}" && -n "${IPv6_address}" ]];then
elif [ -x "$(command -v hostname)" ]; then
hostname=$(hostname -f) # Both IPv4 and IPv6
else cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPv4_address" -v ipv6addr="$IPv6_address" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> ${piholeDir}/${accretionDisc}
echo "::: Error: Unable to determine fully qualified domain name of host"
fi elif [[ -n "${IPv4_address}" && -z "${IPv6_address}" ]];then
# If there is a value in the $piholeIPv6, then IPv6 will be used, so the awk command modified to create a line for both protocols
if [[ -n "${IPv6_address}" ]];then # Only IPv4
# Add hostname and dummy domain to the top of gravity.list to make ping result return a friendlier looking domain! Also allows for an easy way to access the Pi-hole admin console (pi.hole/admin) cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPv4_address" '{sub(/\r$/,""); print ipv4addr" "$0}' >> ${piholeDir}/${accretionDisc}
echo -e "$IPv4addr $hostname\n$IPv6_address $hostname\n$IPv4addr pi.hole\n$IPv6_address pi.hole" > ${piholeDir}/${accretionDisc}
cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPv4addr" -v ipv6addr="$IPv6_address" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> ${piholeDir}/${accretionDisc} elif [[ -z "${IPv4_address}" && -n "${IPv6_address}" ]];then
else
# Otherwise, just create gravity.list as normal using IPv4 # Only IPv6
# Add hostname and dummy domain to the top of gravity.list to make ping result return a friendlier looking domain! Also allows for an easy way to access the Pi-hole admin console (pi.hole/admin) cat ${piholeDir}/${eventHorizon} | awk -v ipv6addr="$IPv6_address" '{sub(/\r$/,""); print ipv6addr" "$0}' >> ${piholeDir}/${accretionDisc}
echo -e "$IPv4addr $hostname\n$IPv4addr pi.hole" > ${piholeDir}/${accretionDisc}
cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPv4addr" '{sub(/\r$/,""); print ipv4addr" "$0}' >> ${piholeDir}/${accretionDisc} elif [[ -z "${IPv4_address}" && -z "${IPv6_address}" ]];then
echo "::: No IP Values found! Please run 'pihole -r' and choose reconfigure to restore values"
exit 1
fi fi
# Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it # Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it
@ -270,20 +267,19 @@ function gravity_hostFormat() {
} }
# blackbody - remove any remnant files from script processes # blackbody - remove any remnant files from script processes
function gravity_blackbody() { gravity_blackbody() {
# Loop through list files # Loop through list files
for file in ${piholeDir}/*.${justDomainsExtension} for file in ${piholeDir}/*.${justDomainsExtension}; do
do
# If list is in active array then leave it (noop) else rm the list # If list is in active array then leave it (noop) else rm the list
if [[ " ${activeDomains[@]} " =~ ${file} ]]; then if [[ " ${activeDomains[@]} " =~ ${file} ]]; then
: :
else else
rm -f "$file" rm -f "${file}"
fi fi
done done
} }
function gravity_advanced() { gravity_advanced() {
# Remove comments and print only the domain name # Remove comments and print only the domain name
# Most of the lists downloaded are already in hosts file format but the spacing/formating is not contigious # 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
@ -296,64 +292,62 @@ function gravity_advanced() {
echo " done!" echo " done!"
numberOf=$(wc -l < ${piholeDir}/${supernova}) numberOf=$(wc -l < ${piholeDir}/${supernova})
echo "::: $numberOf domains being pulled in by gravity..." echo "::: ${numberOf} domains being pulled in by gravity..."
gravity_unique gravity_unique
} }
function gravity_reload() { gravity_reload() {
#Clear no longer needed files... #Clear no longer needed files...
echo ":::" echo ":::"
echo -n "::: Cleaning up un-needed files..." echo -n "::: Cleaning up un-needed files..."
${SUDO} rm ${piholeDir}/pihole.*.txt rm ${piholeDir}/pihole.*.txt
echo " done!" echo " done!"
# Reload hosts file # Reload hosts file
echo ":::" echo ":::"
echo -n "::: Refresh lists in dnsmasq..." echo "::: Refresh lists in dnsmasq..."
#ensure /etc/dnsmasq.d/01-pihole.conf is pointing at the correct list! #ensure /etc/dnsmasq.d/01-pihole.conf is pointing at the correct list!
#First escape forward slashes in the path: #First escape forward slashes in the path:
adList=${adList//\//\\\/} adList=${adList//\//\\\/}
#Now replace the line in dnsmasq file #Now replace the line in dnsmasq file
${SUDO} sed -i "s/^addn-hosts.*/addn-hosts=$adList/" /etc/dnsmasq.d/01-pihole.conf # sed -i "s/^addn-hosts.*/addn-hosts=$adList/" /etc/dnsmasq.d/01-pihole.conf
dnsmasqPid=$(pidof dnsmasq)
find "$piholeDir" -type f -exec ${SUDO} chmod 666 {} \;
if [[ ${dnsmasqPid} ]]; then pihole restartdns
# service already running - reload config
${SUDO} killall -s HUP dnsmasq
else
# service not running, start it up
${SUDO} service dnsmasq start
fi
echo " done!"
} }
for var in "$@"; do
for var in "$@" case "${var}" in
do
case "$var" in
"-f" | "--force" ) forceGrav=true;; "-f" | "--force" ) forceGrav=true;;
"-h" | "--help" ) helpFunc;; "-h" | "--help" ) helpFunc;;
"-sd" | "--skip-download" ) skipDownload=true;;
esac esac
done done
if [[ ${forceGrav} == true ]]; then if [[ "${forceGrav}" == true ]]; then
echo -n "::: Deleting exising list cache..." echo -n "::: Deleting exising list cache..."
${SUDO} rm /etc/pihole/list.* rm /etc/pihole/list.*
echo " done!" echo " done!"
fi fi
#Overwrite adlists.default from /etc/.pihole in case any changes have been made. Changes should be saved in /etc/adlists.list #Overwrite adlists.default from /etc/.pihole in case any changes have been made. Changes should be saved in /etc/adlists.list
${SUDO} cp /etc/.pihole/adlists.default /etc/pihole/adlists.default cp /etc/.pihole/adlists.default /etc/pihole/adlists.default
gravity_collapse gravity_collapse
gravity_spinup gravity_spinup
gravity_Schwarzchild if [[ "${skipDownload}" == false ]]; then
gravity_advanced gravity_Schwarzchild
gravity_hostFormat gravity_advanced
gravity_blackbody else
echo "::: Using cached Event Horizon list..."
numberOf=$(wc -l < ${piholeDir}/${preEventHorizon})
echo "::: $numberOf unique domains trapped in the event horizon."
fi
gravity_Whitelist gravity_Whitelist
gravity_Blacklist gravity_Blacklist
gravity_hostFormat
gravity_blackbody
gravity_reload gravity_reload
pihole status

284
pihole

@ -12,124 +12,59 @@
# Must be root to use this tool # Must be root to use this tool
if [[ ! $EUID -eq 0 ]];then if [[ ! $EUID -eq 0 ]];then
#echo "::: You are root."
#else
#echo "::: Sudo will be used for this tool."
# Check if it is actually installed
# If it isn't, exit because the pihole cannot be invoked without privileges.
if [ -x "$(command -v sudo)" ];then if [ -x "$(command -v sudo)" ];then
export SUDO="sudo" exec sudo bash "$0" "$@"
exit $?
else else
echo "::: Please install sudo or run this as root." echo "::: sudo is needed to run pihole commands. Please run this script as root or install sudo."
exit 1 exit 1
fi fi
fi fi
function whitelistFunc { whitelistFunc() {
shift /opt/pihole/list.sh "$@"
${SUDO} /opt/pihole/whitelist.sh "$@" exit 0
exit 1
} }
function blacklistFunc { blacklistFunc() {
shift /opt/pihole/list.sh "$@"
${SUDO} /opt/pihole/blacklist.sh "$@" exit 0
exit 1
} }
function debugFunc { debugFunc() {
${SUDO} /opt/pihole/piholeDebug.sh /opt/pihole/piholeDebug.sh
exit 1 exit 0
} }
function flushFunc { flushFunc() {
${SUDO} /opt/pihole/piholeLogFlush.sh /opt/pihole/piholeLogFlush.sh
exit 1 exit 0
} }
function updatePiholeFunc { updatePiholeFunc() {
/opt/pihole/update.sh
if [ ! -d "/etc/.pihole" ]; then #This is unlikely exit 0
echo "::: Critical Error: Pi-Hole repo missing from system!" }
echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole"
exit 1;
fi
if [ ! -d "/var/www/html/admin" ]; then #This is unlikely
echo "::: Critical Error: Pi-Hole repo missing from system!"
echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole"
exit 1;
fi
echo "::: Checking for updates..."
piholeVersion=$(cd /etc/.pihole/ && git describe --tags --abbrev=0)
piholeVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//')
webVersion=$(cd /var/www/html/admin/ && git describe --tags --abbrev=0)
webVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//')
echo "::: Pi-hole version is $piholeVersion (Latest version is $piholeVersionLatest)"
echo "::: Web Admin version is $webVersion (Latest version is $webVersionLatest)"
echo ":::"
if [[ ${piholeVersion} == ${piholeVersionLatest} ]] ; then
echo "::: Pi-hole Base files are already up to date! Version: ${piholeVersionLatest}"
echo "::: No need to update!"
echo ":::"
if [[ ${webVersion} == ${webVersionLatest} ]] ; then
echo "::: Web Admin files are already up to date!"
echo "::: No need to update!"
echo ":::"
else
echo "::: An Update is available for the Web Admin!"
echo ":::"
echo "::: Fetching latest changes from GitHub..."
cd /var/www/html/admin
${SUDO} git pull origin master
echo ":::"
echo "::: Pi-hole Web Admin has been updated to ${webVersion}"
echo "::: See https://changes.pi-hole.net for details"
fi
else
echo -n "::: An update is available for "
if [[ ${webVersion} == ${webVersionLatest} ]] ; then
echo " Pi-Hole!"
else
echo " Pi-Hole base files and the Web Admin. Both will be updated!"
fi
echo "::: Fetching latest changes from GitHub..."
cd /etc/.pihole
${SUDO} git pull origin master
${SUDO} /etc/.pihole/automated\ install/basic-install.sh pihole
echo ":::"
echo "::: Pi-hole has been updated to version ${piholeVersionLatest}"
if [[ ${webVersion} != ${webVersionLatest} ]] ; then
echo "::: Web Admin has been updated to version ${webVersionLatest}"
fi
echo ":::"
echo "::: See https://changes.pi-hole.net for details"
fi
exit 1 reconfigurePiholeFunc() {
/etc/.pihole/automated\ install/basic-install.sh --reconfigure
exit 0;
} }
function updateGravityFunc { updateGravityFunc() {
${SUDO} /opt/pihole/gravity.sh "$@" /opt/pihole/gravity.sh "$@"
exit 1 exit 0
} }
function setupLCDFunction { setupLCDFunction() {
${SUDO} /opt/pihole/setupLCD.sh /opt/pihole/setupLCD.sh
exit 1 exit 0
} }
function queryFunc { queryFunc() {
domain=$2 domain=$2
for list in /etc/pihole/list.* for list in /etc/pihole/list.*; do
do
count=$(grep ${domain} $list | wc -l) count=$(grep ${domain} $list | wc -l)
echo "::: ${list} (${count} results)" echo "::: ${list} (${count} results)"
if [[ ${count} > 0 ]]; then if [[ ${count} > 0 ]]; then
@ -137,45 +72,113 @@ function queryFunc {
fi fi
echo "" echo ""
done done
exit 1 exit 0
} }
function chronometerFunc { chronometerFunc() {
shift shift
${SUDO} /opt/pihole/chronometer.sh "$@" /opt/pihole/chronometer.sh "$@"
exit 1 exit 0
} }
function uninstallFunc { uninstallFunc() {
${SUDO} /opt/pihole/uninstall.sh /opt/pihole/uninstall.sh
exit 1 exit 0
} }
function versionFunc { versionFunc() {
${SUDO} /opt/pihole/version.sh shift
exit 1 /opt/pihole/version.sh "$@"
exit 0
}
restartDNS() {
dnsmasqPid=$(pidof dnsmasq)
if [[ ${dnsmasqPid} ]]; then
# service already running - reload config
if [ -x "$(command -v systemctl)" ]; then
systemctl restart dnsmasq
else
service dnsmasq restart
fi
else
# service not running, start it up
if [ -x "$(command -v systemctl)" ]; then
systemctl start dnsmasq
else
service dnsmasq start
fi
fi
} }
function helpFunc { piholeEnable() {
echo "::: Control all PiHole specific functions!" if [[ "${1}" == "0" ]] ; then
echo ":::" #Disable Pihole
echo "::: Usage: pihole [options]" sed -i 's/^addn-hosts/#addn-hosts/' /etc/dnsmasq.d/01-pihole.conf
echo "::: Add -h after -w (whitelist), -b (blacklist), or -c (chronometer) for more information on usage" echo "::: Blocking has been disabled!"
echo ":::" else
echo "::: Options:" #Enable pihole
echo "::: -w, whitelist Whitelist domains" echo "::: Blocking has been enabled!"
echo "::: -b, blacklist Blacklist domains" sed -i 's/^#addn-hosts/addn-hosts/' /etc/dnsmasq.d/01-pihole.conf
echo "::: -d, debug Start a debugging session if having trouble" fi
echo "::: -f, flush Flush the pihole.log file" restartDNS
echo "::: -up, updatePihole Update Pi-hole" }
echo "::: -g, updateGravity Update the list of ad-serving domains"
echo "::: -s, setupLCD Automatically configures the Pi to use the 2.8 LCD screen to display stats on it" piholeStatus() {
echo "::: -c, chronometer Calculates stats and displays to an LCD" if [[ $(cat /etc/dnsmasq.d/01-pihole.conf | grep "#addn-hosts=/") ]] ; then
echo "::: -h, help Show this help dialog" #list is commented out
echo "::: -v, version Show current versions" if [[ "${1}" == "web" ]] ; then
echo "::: -q, query Query the adlists for a specific domain" echo 0;
echo "::: uninstall Uninstall Pi-Hole from your system :(!" else
echo "::: Pi-hole blocking is Disabled";
fi
elif [[ $(cat /etc/dnsmasq.d/01-pihole.conf | grep "addn-hosts=/") ]] ; then
#list set
if [[ "${1}" == "web" ]] ; then
echo 1;
else
echo "::: Pi-hole blocking is Enabled";
fi
else
#addn-host not found
if [[ "${1}" == "web" ]] ; then
echo 99
else
echo "::: No hosts file linked to dnsmasq, adding it in enabled state"
fi
#add addn-host= to dnsmasq
echo "addn-hosts=/etc/pihole/gravity.list" >> /etc/dnsmasq.d/01-pihole.conf
restartDNS
fi
}
helpFunc() {
cat << EOM
::: Control all PiHole specific functions!
:::
::: Usage: pihole [options]
::: Add -h after -w (whitelist), -b (blacklist), or -c (chronometer) for more information on usage
:::
::: Options:
::: -w, whitelist Whitelist domains
::: -b, blacklist Blacklist domains
::: -d, debug Start a debugging session if having trouble
::: -f, flush Flush the pihole.log file
::: -up, updatePihole Update Pi-hole
::: -g, updateGravity Update the list of ad-serving domains
::: -s, setupLCD Automatically configures the Pi to use the 2.8 LCD screen to display stats on it
::: -c, chronometer Calculates stats and displays to an LCD
::: -h, help Show this help dialog
::: -v, version Show current versions
::: -q, query Query the adlists for a specific domain
::: uninstall Uninstall Pi-Hole from your system :(!
::: status Is Pi-Hole Enabled or Disabled
::: enable Enable Pi-Hole DNS Blocking
::: disable Disable Pi-Hole DNS Blocking
::: restartdns Restart dnsmasq
EOM
exit 1 exit 1
} }
@ -184,18 +187,23 @@ if [[ $# = 0 ]]; then
fi 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" ) whitelistFunc "$@";;
"-b" | "blacklist" ) blacklistFunc "$@";; "-b" | "blacklist" ) blacklistFunc "$@";;
"-d" | "debug" ) debugFunc;; "-d" | "debug" ) debugFunc;;
"-f" | "flush" ) flushFunc;; "-f" | "flush" ) flushFunc;;
"-up" | "updatePihole" ) updatePiholeFunc;; "-up" | "updatePihole" ) updatePiholeFunc;;
"-g" | "updateGravity" ) updateGravityFunc "$@";; "-r" | "reconfigure" ) reconfigurePiholeFunc;;
"-s" | "setupLCD" ) setupLCDFunction;; "-g" | "updateGravity" ) updateGravityFunc "$@";;
"-c" | "chronometer" ) chronometerFunc "$@";; "-s" | "setupLCD" ) setupLCDFunction;;
"-h" | "help" ) helpFunc;; "-c" | "chronometer" ) chronometerFunc "$@";;
"-v" | "version" ) versionFunc;; "-h" | "help" ) helpFunc;;
"-q" | "query" ) queryFunc "$@";; "-v" | "version" ) versionFunc "$@";;
"uninstall" ) uninstallFunc;; "-q" | "query" ) queryFunc "$@";;
* ) helpFunc;; "uninstall" ) uninstallFunc;;
"enable" ) piholeEnable 1;;
"disable" ) piholeEnable 0;;
"status" ) piholeStatus "$2";;
"restartdns" ) restartDNS;;
* ) helpFunc;;
esac esac

Loading…
Cancel
Save