diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 00000000..e1cb3b50 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,3 @@ +engines: + shellcheck: + enabled: true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..57faaa8b --- /dev/null +++ b/.gitattributes @@ -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 diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index fc2d528e..53f5b429 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -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). -- [ ] 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)). +- [] 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'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?:** -- [ ] 1 (very unfamiliar) -- [ ] 2 -- [ ] 3 -- [ ] 4 -- [ ] 5 -- [ ] 6 -- [ ] 7 -- [ ] 8 -- [ ] 9 -- [ ] 10 (very familiar) +- [] 1 (very unfamiliar) +- [] 2 +- [] 3 +- [] 4 +- [] 5 +- [] 6 +- [] 7 +- [] 8 +- [] 9 +- [] 10 (very familiar) --- **[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`:** `http://termbin.com/` + +_This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._ diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3eb26862..7291be41 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -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 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 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 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 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 give this submission freely, and claim no ownership to its content. **How familiar are you with the codebase?:** -- [ ] 1 (very unfamiliar) -- [ ] 2 -- [ ] 3 -- [ ] 4 -- [ ] 5 -- [ ] 6 -- [ ] 7 -- [ ] 8 -- [ ] 9 -- [ ] 10 (very familiar) +- [] 1 (very unfamiliar) +- [] 2 +- [] 3 +- [] 4 +- [] 5 +- [] 6 +- [] 7 +- [] 8 +- [] 9 +- [] 10 (very familiar) --- _{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)._ diff --git a/.pullapprove.yml b/.pullapprove.yml index db3c0a90..3b421dd2 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -1,19 +1,38 @@ -approve_by_comment: true -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 +version: 2 + always_pending: - title_regex: '(WIP|wip)' + title_regex: '(WIP|wip)' labels: - wip explanation: 'This PR is a work in progress...' + +group_defaults: + reset_on_push: + enabled: true + reject_value: -2 + approve_regex: '^(Approved|:shipit:|:\+1:|Engage)' + 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 diff --git a/.github/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 100% rename from .github/CONTRIBUTING.md rename to CONTRIBUTING.md diff --git a/README.md b/README.md index 4c242d56..b28b3f3e 100644 --- a/README.md +++ b/README.md @@ -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 @@ -8,17 +8,15 @@ Works on most Debian and CentOS/RHEL based distributions! 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!) -## `curl -L https://install.pi-hole.net | bash` +### `curl -sSL https://install.pi-hole.net | bash` ### Alternative Semi-Automated install ```bash wget -O basic-install.sh https://install.pi-hole.net -chmod +x basic-install.sh -./basic-install.sh +cat basic-install.sh | bash ``` - -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 +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. 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 -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) - ![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 - [@The_Pi_Hole](https://twitter.com/The_Pi_Hole) +- [Discourse](https://discourse.pi-hole.net/) - [/r/pihole](https://www.reddit.com/r/pihole/) - [Pi-hole YouTube channel](https://www.youtube.com/channel/UCT5kq9w0wSjogzJb81C9U0w) - [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) ## 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. +#### 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 -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 @@ -67,13 +70,13 @@ The [Web interface](https://github.com/jacobsalmela/AdminLTE#pi-hole-admin-dashb ### 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 A basic read-only API can be accessed at `/admin/api.php`. It returns the following JSON: -```json +``` json { "domains_being_blocked": "136708", "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) - [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/) - -## 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. diff --git a/adlists.default b/adlists.default index 5a803400..57860b3f 100644 --- a/adlists.default +++ b/adlists.default @@ -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: # # 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 #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: #https://raw.githubusercontent.com/reek/anti-adblock-killer/master/anti-adblock-killer-filters.txt #https://raw.githubusercontent.com/Dawsey21/Lists/master/main-blacklist.txt diff --git a/advanced/01-pihole.conf b/advanced/01-pihole.conf index 339bbf90..f4707ef4 100644 --- a/advanced/01-pihole.conf +++ b/advanced/01-pihole.conf @@ -9,53 +9,41 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# If you want dnsmasq to read another file, as well as /etc/hosts, use -# this. +############################################################################### +# FILE AUTOMATICALLY POPULATED BY PI-HOLE INSTALL/UPDATE PROCEDURE. # +# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE # +# # +# IF YOU WISH TO CHANGE THE UPSTREAM SERVERS, CHANGE THEM IN: # +# /etc/pihole/setupVars.conf # +# # +# ANY OTHER CHANGES SHOULD BE MADE IN A SEPERATE CONFIG FILE # +# OR IN /etc/dnsmasq.conf # +############################################################################### + +address=/pi.hole/@IPv4@ +address=/pi.hole/@IPv6@ + +address=/@HOSTNAME@/@IPv4@ +address=/@HOSTNAME@/@IPv6@ + addn-hosts=/etc/pihole/gravity.list -# The following two options make you a better netizen, since they -# tell dnsmasq to filter out queries which the public DNS cannot -# answer, and which load the servers (especially the root servers) -# unnecessarily. If you have a dial-on-demand link they also stop -# these requests from bringing up the link unnecessarily. - -# Never forward plain names (without a dot or domain part) domain-needed -# Never forward addresses in the non-routed address spaces. + bogus-priv -# If you don't want dnsmasq to read /etc/resolv.conf or any other -# file, getting its servers from this file instead (see below), then -# uncomment this. no-resolv -# Add other name servers here, with domain specs if they are for -# non-public domains. server=@DNS1@ server=@DNS2@ -# If you want dnsmasq to listen for DHCP and DNS requests only on -# specified interfaces (and the loopback) give the name of the -# interface (eg eth0) here. interface=@INT@ -# Or which to listen on by address (remember to include 127.0.0.1 if -# you use this.) -listen-address=127.0.0.1 -# Set the cachesize here. cache-size=10000 -# For debugging purposes, log each DNS query as it passes through -# dnsmasq. log-queries log-facility=/var/log/pihole.log -# Normally responses which come from /etc/hosts and the DHCP lease -# file have Time-To-Live set as zero, which conventionally means -# do not cache further. If you are happy to trade lower load on the -# server for potentially stale date, you can set a time-to-live (in -# seconds) here. local-ttl=300 -# This allows it to continue functioning without being blocked by syslog, and allows syslog to use dnsmasq for DNS queries without risking deadlock log-async diff --git a/advanced/Scripts/blacklist.sh b/advanced/Scripts/blacklist.sh deleted file mode 100755 index a289a9a5..00000000 --- a/advanced/Scripts/blacklist.sh +++ /dev/null @@ -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 diff --git a/advanced/Scripts/chronometer.sh b/advanced/Scripts/chronometer.sh index eae7cf1c..2c305d53 100755 --- a/advanced/Scripts/chronometer.sh +++ b/advanced/Scripts/chronometer.sh @@ -17,11 +17,11 @@ gravity="/etc/pihole/gravity.list" today=$(date "+%b %e") -function CalcBlockedDomains(){ +CalcBlockedDomains() { CheckIPv6 - if [ -e "$gravity" ]; then + if [ -e "${gravity}" ]; then #Are we IPV6 or IPV4? - if [[ -n ${piholeIPv6} ]];then + if [[ -n ${piholeIPv6} ]]; then #We are IPV6 blockedDomainsTotal=$(wc -l /etc/pihole/gravity.list | awk '{print $1/2}') else @@ -33,43 +33,43 @@ function CalcBlockedDomains(){ fi } -function CalcQueriesToday(){ - if [ -e "$piLog" ];then - queriesToday=$(cat "$piLog" | grep "$today" | awk '/query/ {print $6}' | wc -l) +CalcQueriesToday() { + if [ -e "${piLog}" ]; then + queriesToday=$(cat "${piLog}" | grep "${today}" | awk '/query/ {print $6}' | wc -l) else queriesToday="Err." fi } -function CalcblockedToday(){ - if [ -e "$piLog" ] && [ -e "$gravity" ];then +CalcblockedToday() { + if [ -e "${piLog}" ] && [ -e "${gravity}" ];then blockedToday=$(cat ${piLog} | awk '/\/etc\/pihole\/gravity.list/ && !/address/ {print $6}' | wc -l) else blockedToday="Err." fi } -function CalcPercentBlockedToday(){ - if [ "$queriesToday" != "Err." ] && [ "$blockedToday" != "Err." ]; then - if [ "$queriesToday" != 0 ]; then #Fixes divide by zero error :) - #scale 2 rounds the number down, so we'll do scale 4 and then trim the last 2 zeros - percentBlockedToday=$(echo "scale=4; $blockedToday/$queriesToday*100" | bc) - percentBlockedToday=$(sed 's/.\{2\}$//' <<< "$percentBlockedToday") +CalcPercentBlockedToday() { + if [ "${queriesToday}" != "Err." ] && [ "${blockedToday}" != "Err." ]; then + if [ "${queriesToday}" != 0 ]; then #Fixes divide by zero error :) + #scale 2 rounds the number down, so we'll do scale 4 and then trim the last 2 zeros + percentBlockedToday=$(echo "scale=4; ${blockedToday}/${queriesToday}*100" | bc) + percentBlockedToday=$(sed 's/.\{2\}$//' <<< "${percentBlockedToday}") else percentBlockedToday=0 fi fi } -function CheckIPv6(){ +CheckIPv6() { piholeIPv6file="/etc/pihole/.useIPv6" if [[ -f ${piholeIPv6file} ]];then - # If the file exists, then the user previously chose to use IPv6 in the automated installer - piholeIPv6=$(ip -6 route get 2001:4860:4860::8888 | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "src") print $(i+1) }') + # If the file exists, then the user previously chose to use IPv6 in the automated installer + piholeIPv6=$(ip -6 route get 2001:4860:4860::8888 | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "src") print $(i+1) }') fi } -function outputJSON(){ +outputJSON() { CalcQueriesToday CalcblockedToday 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" } -function normalChrono(){ - for (( ; ; )) - do +normalChrono() { + for (( ; ; )); do clear # Displays a colorful Pi-hole logo echo " ___ _ _ _" @@ -111,26 +110,27 @@ function normalChrono(){ CalcBlockedDomains - echo "Blocking: $blockedDomainsTotal" + echo "Blocking: ${blockedDomainsTotal}" #below commented line does not add up to todaysQueryCount #echo "Queries: $todaysQueryCountV4 / $todaysQueryCountV6" - echo "Queries: $queriesToday" #same total calculation as dashboard - echo "Pi-holed: $blockedToday ($percentBlockedToday%)" + echo "Queries: ${queriesToday}" #same total calculation as dashboard + echo "Pi-holed: ${blockedToday} (${percentBlockedToday}%)" sleep 5 done } -function displayHelp(){ - echo "::: Displays stats about your piHole!" - echo ":::" - echo "::: Usage: sudo pihole -c [optional:-j]" - echo "::: Note: If no option is passed, then stats are displayed on screen, updated every 5 seconds" - echo ":::" - echo "::: Options:" - echo "::: -j, --json output stats as JSON formatted string" - echo "::: -h, --help display this help text" - +displayHelp() { + cat << EOM +::: Displays stats about your piHole! +::: +::: Usage: sudo pihole -c [optional:-j] +::: Note: If no option is passed, then stats are displayed on screen, updated every 5 seconds +::: +::: Options: +::: -j, --json output stats as JSON formatted string +::: -h, --help display this help text +EOM exit 1 } @@ -138,11 +138,10 @@ if [[ $# = 0 ]]; then normalChrono fi -for var in "$@" -do - case "$var" in - "-j" | "--json" ) outputJSON;; - "-h" | "--help" ) displayHelp;; - * ) exit 1;; - esac +for var in "$@"; do + case "$var" in + "-j" | "--json" ) outputJSON;; + "-h" | "--help" ) displayHelp;; + * ) exit 1;; + esac done diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh new file mode 100644 index 00000000..24f6d055 --- /dev/null +++ b/advanced/Scripts/list.sh @@ -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 + diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index aadb083b..6768a8ea 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -13,452 +13,381 @@ set -o pipefail ######## GLOBAL VARS ######## +VARSFILE="/etc/pihole/setupVars.conf" DEBUG_LOG="/var/log/pihole_debug.log" DNSMASQFILE="/etc/dnsmasq.conf" -PIHOLECONFFILE="/etc/dnsmasq.d/01-pihole.conf" +DNSMASQCONFFILE="/etc/dnsmasq.d/01-pihole.conf" LIGHTTPDFILE="/etc/lighttpd/lighttpd.conf" LIGHTTPDERRFILE="/var/log/lighttpd/error.log" GRAVITYFILE="/etc/pihole/gravity.list" -HOSTSFILE="/etc/hosts" WHITELISTFILE="/etc/pihole/whitelist.txt" BLACKLISTFILE="/etc/pihole/blacklist.txt" -ADLISTSFILE="/etc/pihole/adlists.list" +ADLISTFILE="/etc/pihole/adlists.list" PIHOLELOG="/var/log/pihole.log" WHITELISTMATCHES="/tmp/whitelistmatches.list" +IPV6_READY=false + # Header info and introduction -echo "::: Beginning Pi-hole debug at $(date)!" -echo "::: This debugging process will collect information from your running configuration," -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" -echo "::: person who is given the unique URL. Please consider where you post this link." -echo "::: " - - -######## FIRST CHECK ######## -# Must be root to debug -if [[ "$EUID" -eq 0 ]]; then - echo "::: Script is executing as root user..." -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 +cat << EOM +::: Beginning Pi-hole debug at $(date)! +::: +::: This process collects information from your Pi-hole, and optionally uploads +::: it to a unique and random directory on tricorder.pi-hole.net. +::: +::: 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 +::: secure your data and will work to further reduce any personal information gathered. +::: +::: Please read and note any issues, and follow any directions advised during this process. +EOM # Ensure the file exists, create if not, clear if exists. -if [ ! -f "$DEBUG_LOG" ]; then - ${SUDO} touch ${DEBUG_LOG} - ${SUDO} chmod 644 ${DEBUG_LOG} - ${SUDO} chown "$USER":root ${DEBUG_LOG} -else - truncate -s 0 ${DEBUG_LOG} -fi +truncate --size=0 "${DEBUG_LOG}" +chmod 644 ${DEBUG_LOG} +chown "$USER":pihole ${DEBUG_LOG} + +source ${VARSFILE} ### Private functions exist here ### -function log_write { - echo "$1" >> "${DEBUG_LOG}" +log_write() { + echo "${1}" >> "${DEBUG_LOG}" } -function version_check { - log_write "############################################################" - log_write "########## Installed Versions ##########" - log_write "############################################################" - - echo "::: Detecting Pi-hole installed versions." - pi_hole_ver="$(cd /etc/.pihole/ && git describe --tags --abbrev=0)" \ - && log_write "Pi-hole Version: $pi_hole_ver" || log_write "Pi-hole git repository not detected." - admin_ver="$(cd /var/www/html/admin && git describe --tags --abbrev=0)" \ - && log_write "WebUI Version: $admin_ver" || log_write "Pi-hole Admin Pages git repository not detected." - - echo "::: Writing lighttpd version to logfile." - light_ver="$(lighttpd -v |& head -n1)" && log_write "${light_ver}" || log_write "lighttpd not installed." - - echo "::: Writing PHP version to logfile." - php_ver="$(php -v |& head -n1)" && log_write "${php_ver}" || log_write "PHP not installed." +log_echo() { + case ${1} in + -n) + echo -n "::: ${2}" + log_write "${2}" + ;; + -r) + echo "::: ${2}" + log_write "${2}" + ;; + -l) + echo "${2}" + log_write "${2}" + ;; + *) + echo "::: ${1}" + log_write "${1}" + esac } -function distro_check { - echo "############################################################" >> ${DEBUG_LOG} - echo "######## Installed OS Distribution #########" >> ${DEBUG_LOG} - echo "############################################################" >> ${DEBUG_LOG} - - echo "::: Checking installed OS Distribution release." - TMP=$(cat /etc/*release || echo "Failed to find release") - - echo "::: Writing OS Distribution release to logfile." - echo "$TMP" >> ${DEBUG_LOG} - echo >> ${DEBUG_LOG} +header_write() { + log_echo "" + log_echo "${1}" + log_write "" } -function ip_check { - echo "############################################################" >> ${DEBUG_LOG} - echo "######## IP Address Information #########" >> ${DEBUG_LOG} - echo "############################################################" >> ${DEBUG_LOG} +file_parse() { + while read -r line; do + if [ ! -z "${line}" ]; then + [[ "${line}" =~ ^#.*$ || ! "${line}" ]] && continue + log_write "${line}" + fi + done < "${1}" + log_write "" +} - 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} +block_parse() { + log_write "${1}" +} - 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} +lsof_parse() { + local user + local process - 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} + user=$(echo ${1} | cut -f 3 -d ' ' | cut -c 2-) + process=$(echo ${1} | cut -f 2 -d ' ' | cut -c 2-) + [[ ${2} -eq ${process} ]] \ + && echo "::: Correctly configured." \ + || log_echo "::: Failure: Incorrectly configured daemon." - 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 + log_write "Found user ${user} with process ${process}" +} - GATEWAY6=$(ip -6 r | grep default | cut -d ' ' -f 3) - if [[ $? = 0 ]] - 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..." - GATEWAY6_CHECK=$(ping6 -q -w 3 -c 3 -n 2001:4860:4860::8888 | tail -n3) - if [[ $? = 0 ]] - then - echo "IPv6 Internet check:" >> ${DEBUG_LOG} - else - echo "IPv6 Internet check failed:" >> ${DEBUG_LOG} - fi +version_check() { + header_write "Detecting Installed Package Versions:" + local error_found + error_found=0 + + local pi_hole_ver="$(cd /etc/.pihole/ && git describe --tags --abbrev=0)" \ + && log_echo -r "Pi-hole: $pi_hole_ver" || (log_echo "Pi-hole git repository not detected." && error_found=1) + local admin_ver="$(cd /var/www/html/admin && git describe --tags --abbrev=0)" \ + && log_echo -r "WebUI: $admin_ver" || (log_echo "Pi-hole Admin Pages git repository not detected." && error_found=1) + 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 + log_echo "${1} not found!" + return 1 + fi + 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" +} + +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}" +} + +processor_check() { + header_write "Checking processor variety" + log_write $(uname -m) && return 0 || return 1 +} + +ipv6_check() { + # Check if system is IPv6 enabled, for use in other functions + if [[ $IPv6_address ]]; then + ls /proc/net/if_inet6 &>/dev/null && IPV6_READY=true + return 0 + else + return 1 + fi +} + + +ip_check() { + header_write "IP Address Information" + # Get the current interface for Internet traffic + + # 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 - GATEWAY_CHECK="No IPv6 Gateway Detected" + log_echo="No IPv6 Gateway Detected" fi - echo "$GATEWAY_CHECK" >> ${DEBUG_LOG} +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." - echo >> ${DEBUG_LOG} + 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 hostnameCheck { - echo "############################################################" >> ${DEBUG_LOG} - echo "######## Hostname Information #########" >> ${DEBUG_LOG} - echo "############################################################" >> ${DEBUG_LOG} +port_check() { + local lsof_value - echo "::: Writing locally configured hostnames to logfile" - # Write the hostname output to compare against entries in /etc/hosts, which is logged next - echo "This Pi-hole is: $(hostname)" >> ${DEBUG_LOG} - - echo "::: Writing hosts file to debug log..." - echo "### Hosts ###" >> ${DEBUG_LOG} - - if [ -e "$HOSTSFILE" ] - then - cat "$HOSTSFILE" >> ${DEBUG_LOG} - echo >> ${DEBUG_LOG} - else - echo "No hosts file found!" >> ${DEBUG_LOG} - printf ":::\tNo hosts file found!\n" - fi + lsof_value=$(lsof -i ${1}:${2} -FcL | tr '\n' ' ') \ + && lsof_parse "${lsof_value}" "${3}" \ + || log_echo "Failure: IPv${1} Port not in use" } -function portCheck { - echo "############################################################" >> ${DEBUG_LOG} - echo "######## Open Port Information #########" >> ${DEBUG_LOG} - echo "############################################################" >> ${DEBUG_LOG} +daemon_check() { + # Check for daemon ${1} on port ${2} + header_write "Daemon Process Information" - echo "::: Detecting local server port 80 and 53 processes." + echo "::: Checking ${2} port for ${1} listener." - ${SUDO} lsof -i :80 >> ${DEBUG_LOG} - ${SUDO} lsof -i :53 >> ${DEBUG_LOG} - echo >> ${DEBUG_LOG} + if [[ ${IPV6_READY} ]]; then + port_check 6 "${2}" "${1}" + fi + lsof_value=$(lsof -i 4:${2} -FcL | tr '\n' ' ') \ + port_check 4 "${2}" "${1}" } -function testResolver { - echo "############################################################" >> ${DEBUG_LOG} - echo "############ Resolver Functions Check ############" >> ${DEBUG_LOG} - echo "############################################################" >> ${DEBUG_LOG} - +testResolver() { + header_write "Resolver Functions Check" # Find a blocked url that has not been whitelisted. - TESTURL="doubleclick.com" - if [ -s "$WHITELISTMATCHES" ]; then + TESTURL="doubleclick.com" + if [ -s "${WHITELISTMATCHES}" ]; then while read -r line; do CUTURL=${line#*" "} - if [ "$CUTURL" != "Pi-Hole.IsWorking.OK" ]; then + if [ "${CUTURL}" != "Pi-Hole.IsWorking.OK" ]; then while read -r line2; do CUTURL2=${line2#*" "} - if [ "$CUTURL" != "$CUTURL2" ]; then - TESTURL="$CUTURL" + if [ "${CUTURL}" != "${CUTURL2}" ]; then + TESTURL="${CUTURL}" break 2 fi - done < "$WHITELISTMATCHES" + done < "${WHITELISTMATCHES}" fi - done < "$GRAVITYFILE" + done < "${GRAVITYFILE}" fi - echo "Resolution of $TESTURL from Pi-hole:" >> ${DEBUG_LOG} - LOCALDIG=$(dig "$TESTURL" @127.0.0.1) - if [[ $? = 0 ]] - then - echo "$LOCALDIG" >> ${DEBUG_LOG} + log_write "Resolution of ${TESTURL} from Pi-hole:" + LOCALDIG=$(dig "${TESTURL}" @127.0.0.1) + if [[ $? = 0 ]]; then + log_write "${LOCALDIG}" else - echo "Failed to resolve $TESTURL on Pi-hole" >> ${DEBUG_LOG} + log_write "Failed to resolve ${TESTURL} on Pi-hole" fi - echo >> ${DEBUG_LOG} + log_write "" - echo "Resolution of $TESTURL from 8.8.8.8:" >> ${DEBUG_LOG} - REMOTEDIG=$(dig "$TESTURL" @8.8.8.8) - if [[ $? = 0 ]] - then - echo "$REMOTEDIG" >> ${DEBUG_LOG} + log_write "Resolution of ${TESTURL} from 8.8.8.8:" + REMOTEDIG=$(dig "${TESTURL}" @8.8.8.8) + if [[ $? = 0 ]]; then + log_write "${REMOTEDIG}" 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 - echo >> ${DEBUG_LOG} + log_write "" - echo "Pi-hole dnsmasq specific records lookups" >> ${DEBUG_LOG} - echo "Cache Size:" >> ${DEBUG_LOG} - dig +short chaos txt cachesize.bind >> ${DEBUG_LOG} - echo "Insertions count:" >> ${DEBUG_LOG} - 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} - echo >> ${DEBUG_LOG} + log_write "Pi-hole dnsmasq specific records lookups" + log_write "Cache Size:" + dig +short chaos txt cachesize.bind >> ${DEBUG_LOG} + log_write "Upstream Servers:" + dig +short chaos txt servers.bind >> ${DEBUG_LOG} + log_write "" } -function checkProcesses { - echo "#######################################" >> ${DEBUG_LOG} - echo "########### Processes Check ###########" >> ${DEBUG_LOG} - echo "#######################################" >> ${DEBUG_LOG} - echo ":::" - echo "::: Logging status of lighttpd and dnsmasq..." +checkProcesses() { + header_write "Processes Check" + + echo "::: Logging status of lighttpd and dnsmasq..." PROCESSES=( lighttpd dnsmasq ) - for i in "${PROCESSES[@]}" - do - echo "" >> ${DEBUG_LOG} - echo -n "$i" >> "$DEBUG_LOG" - echo " processes status:" >> ${DEBUG_LOG} - ${SUDO} systemctl -l status "$i" >> "$DEBUG_LOG" + for i in "${PROCESSES[@]}"; do + log_write "" + log_write "${i}" + log_write " processes status:" + systemctl -l status "${i}" >> "${DEBUG_LOG}" done - echo >> ${DEBUG_LOG} + log_write "" } -function debugLighttpd { - echo "::: Writing lighttpd to debug log..." - echo "#######################################" >> ${DEBUG_LOG} - echo "############ lighttpd.conf ############" >> ${DEBUG_LOG} - echo "#######################################" >> ${DEBUG_LOG} - 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} +debugLighttpd() { + echo "::: Checking for necessary lighttpd files." + files_check "${LIGHTTPDFILE}" + files_check "${LIGHTTPDERRFILE}" + echo ":::" } ### END FUNCTIONS ### -version_check -distro_check +# Gather version of required packages / repositories +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 -hostnameCheck -portCheck + +daemon_check lighttpd http +daemon_check dnsmasq domain checkProcesses testResolver debugLighttpd -echo "::: Writing dnsmasq.conf to debug log..." -echo "#######################################" >> ${DEBUG_LOG} -echo "############### Dnsmasq ###############" >> ${DEBUG_LOG} -echo "#######################################" >> ${DEBUG_LOG} -if [ -e "$DNSMASQFILE" ] -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 +files_check "${DNSMASQFILE}" +files_check "${DNSMASQCONFFILE}" +files_check "${WHITELISTFILE}" +files_check "${BLACKLISTFILE}" +files_check "${ADLISTFILE}" -### 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 -function dumpPiHoleLog { +dumpPiHoleLog() { 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 "#######################################" >> ${DEBUG_LOG} - echo "############# pihole.log ##############" >> ${DEBUG_LOG} - echo "#######################################" >> ${DEBUG_LOG} - if [ -e "$PIHOLELOG" ] - then + echo "::: " + echo "::: --= User Action Required =--" + 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.)" + header_write "pihole.log" + if [ -e "${PIHOLELOG}" ]; then while true; do - tail -f "$PIHOLELOG" >> ${DEBUG_LOG} - echo >> ${DEBUG_LOG} + tail -f "${PIHOLELOG}" >> ${DEBUG_LOG} + log_write "" done else - echo "No pihole.log file found!" >> ${DEBUG_LOG} + log_write "No pihole.log file found!" printf ":::\tNo pihole.log file found!\n" fi } # Anything to be done after capturing of pihole.log terminates -function finalWork { - echo "::: Finshed debugging!" - echo "::: The debug log can be uploaded to Termbin.com for easier sharing." - read -r -p "::: Would you like to upload the log? [y/N] " response - case ${response} in - [yY][eE][sS]|[yY]) - TERMBIN=$(cat /var/log/pihole_debug.log | nc termbin.com 9999) - ;; - *) - echo "::: Log will NOT be uploaded to Termbin." - ;; - esac +finalWork() { + local tricorder + echo "::: Finshed debugging!" + 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 + case ${response} in + [yY][eE][sS]|[yY]) + tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999) + ;; + *) + echo "::: Log will NOT be uploaded to tricorder." + ;; + esac - # Check if termbin.com is reachable. When it's not, point to local log instead - if [ -n "$TERMBIN" ] - then - echo "::: Debug log can be found at : $TERMBIN" - else - echo "::: Debug log can be found at : /var/log/pihole_debug.log" - fi + # Check if tricorder.pi-hole.net is reachable and provide token. + if [ -n "${tricorder}" ]; then + echo "::: Your debug token is : ${tricorder}" + echo "::: Please contact the Pi-hole team with your token to being assistance." + echo "::: Thank you." + fi + echo "::: Debug log can be found at : /var/log/pihole_debug.log" } trap finalWork EXIT diff --git a/advanced/Scripts/setupLCD.sh b/advanced/Scripts/setupLCD.sh index c77f1f4a..e5a01911 100755 --- a/advanced/Scripts/setupLCD.sh +++ b/advanced/Scripts/setupLCD.sh @@ -11,47 +11,32 @@ # (at your option) any later version. ############ FUNCTIONS ########### -# Run this script as root or under sudo -echo ":::" -if [[ $EUID -eq 0 ]];then - echo "::: You are root." -else - echo "::: sudo will be used." - # Check if it is actually installed - # If it isn't, exit because the install cannot complete - if [ -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 # https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L324-L334 getInitSys() { - if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then - SYSTEMD=1 - elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then - SYSTEMD=0 - else - echo "Unrecognised init system" - return 1 - fi + if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then + SYSTEMD=1 + elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then + SYSTEMD=0 + else + echo "Unrecognised init system" + return 1 + fi } # Borrowed from adafruit-pitft-helper: # https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L274-L285 autoLoginPiToConsole() { - if [ -e /etc/init.d/lightdm ]; then - if [ ${SYSTEMD} -eq 1 ]; then - ${SUDO} systemctl set-default multi-user.target - ${SUDO} ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service - else - ${SUDO} update-rc.d lightdm disable 2 - ${SUDO} sed /etc/inittab -i -e "s/1:2345:respawn:\/sbin\/getty --noclear 38400 tty1/1:2345:respawn:\/bin\/login -f pi tty1 <\/dev\/tty1 >\/dev\/tty1 2>&1/" - fi - fi + if [ -e /etc/init.d/lightdm ]; then + if [ ${SYSTEMD} -eq 1 ]; then + systemctl set-default multi-user.target + ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service + else + update-rc.d lightdm disable 2 + sed /etc/inittab -i -e "s/1:2345:respawn:\/sbin\/getty --noclear 38400 tty1/1:2345:respawn:\/bin\/login -f pi tty1 <\/dev\/tty1 >\/dev\/tty1 2>&1/" + fi + fi } ######### SCRIPT ########### @@ -66,23 +51,23 @@ echo /usr/local/bin/chronometer.sh >> /home/pi/.bashrc # Set up the LCD screen based on Adafruits instuctions: # https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/easy-install -curl -SLs https://apt.adafruit.com/add-pin | ${SUDO} bash -${SUDO} apt-get -y install raspberrypi-bootloader -${SUDO} apt-get -y install adafruit-pitft-helper -${SUDO} adafruit-pitft-helper -t 28r +curl -SLs https://apt.adafruit.com/add-pin | bash +apt-get -y install raspberrypi-bootloader +apt-get -y install adafruit-pitft-helper +adafruit-pitft-helper -t 28r # Download the cmdline.txt file that prevents the screen from going blank after a period of time -${SUDO} mv /boot/cmdline.txt /boot/cmdline.orig -${SUDO} curl -o /boot/cmdline.txt https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/cmdline.txt +mv /boot/cmdline.txt /boot/cmdline.orig +curl -o /boot/cmdline.txt https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/cmdline.txt # Back up the original file and download the new one -${SUDO} mv /etc/default/console-setup /etc/default/console-setup.orig -${SUDO} curl -o /etc/default/console-setup https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/console-setup +mv /etc/default/console-setup /etc/default/console-setup.orig +curl -o /etc/default/console-setup https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/console-setup # 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: # http://unix.stackexchange.com/questions/170063/start-a-process-on-a-different-tty diff --git a/advanced/Scripts/update.sh b/advanced/Scripts/update.sh new file mode 100644 index 00000000..a2220d57 --- /dev/null +++ b/advanced/Scripts/update.sh @@ -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 diff --git a/advanced/Scripts/version.sh b/advanced/Scripts/version.sh index e7e7c782..ca78032a 100644 --- a/advanced/Scripts/version.sh +++ b/advanced/Scripts/version.sh @@ -3,18 +3,98 @@ # (c) 2015, 2016 by Jacob Salmela # Network-wide ad blocking via your Raspberry Pi # http://pi-hole.net -# Whitelists domains +# shows version numbers # # 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. -piholeVersion=$(cd /etc/.pihole/ && git describe --tags --abbrev=0) -webVersion=$(cd /var/www/html/admin/ && git describe --tags --abbrev=0) +# Flags: +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/",$//') -webVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//') +normalOutput() { + 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)" -echo "::: Web-Admin version is $webVersion (Latest version is $webVersionLatest)" \ No newline at end of file + 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/",$//') + 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 diff --git a/advanced/Scripts/whitelist.sh b/advanced/Scripts/whitelist.sh deleted file mode 100755 index 75d62173..00000000 --- a/advanced/Scripts/whitelist.sh +++ /dev/null @@ -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 diff --git a/advanced/bash-completion/pihole b/advanced/bash-completion/pihole index 2d6aafae..dd3f050d 100644 --- a/advanced/bash-completion/pihole +++ b/advanced/bash-completion/pihole @@ -1,12 +1,11 @@ -_pihole() -{ - local cur prev opts - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - opts="blacklist chronometer debug flush help query setupLCD uninstall updateDashboard updateGravity updatePihole version whitelist" +_pihole() { + local cur prev opts + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts="blacklist chronometer debug flush help query reconfigure setupLCD uninstall updateGravity updatePihole version whitelist" - COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) - return 0 + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 } -complete -F _pihole pihole \ No newline at end of file +complete -F _pihole pihole diff --git a/advanced/lighttpd.conf.debian b/advanced/lighttpd.conf.debian index 8b62f448..15821bc7 100644 --- a/advanced/lighttpd.conf.debian +++ b/advanced/lighttpd.conf.debian @@ -12,6 +12,7 @@ server.modules = ( "mod_access", "mod_accesslog", + "mod_auth", "mod_expire", "mod_compress", "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 $HTTP["url"] =~ "^(?!/admin)/.*" { # Create a response header for debugging using curl -I setenv.add-response-header = ( "X-Pi-hole" => "A black hole for Internet advertisements." ) - # rewrite only js requests - url.rewrite = ("(.*).js" => "pihole/index.js") } + +# Add user chosen options held in external file +include_shell "cat external.conf 2>/dev/null" diff --git a/advanced/lighttpd.conf.fedora b/advanced/lighttpd.conf.fedora index 8b8e0692..96e1311e 100644 --- a/advanced/lighttpd.conf.fedora +++ b/advanced/lighttpd.conf.fedora @@ -11,6 +11,7 @@ server.modules = ( "mod_access", + "mod_auth", "mod_fastcgi", "mod_accesslog", "mod_expire", @@ -69,10 +70,14 @@ $HTTP["url"] =~ "^/admin/" { 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 $HTTP["url"] =~ "^(?!/admin)/.*" { # Create a response header for debugging using curl -I setenv.add-response-header = ( "X-Pi-hole" => "A black hole for Internet advertisements." ) - # rewrite only js requests - url.rewrite = ("(.*).js" => "pihole/index.js") } + +# Add user chosen options held in external file +include_shell "cat external.conf 2>/dev/null" diff --git a/advanced/pihole.cron b/advanced/pihole.cron index 2d06fbbc..77b7c1ca 100644 --- a/advanced/pihole.cron +++ b/advanced/pihole.cron @@ -8,6 +8,11 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. +# +# This 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 # Download any updates from the adlists @@ -16,10 +21,6 @@ # Pi-hole: Update Pi-hole! Uncomment to enable auto update #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 # Stats will be viewable in the Web interface thanks to the cron job above 00 00 * * * root /usr/local/bin/pihole flush diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index 13e546ba..0ac7f5e4 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -32,29 +32,39 @@ useUpdateVars=false IPv4_address="" IPv6_address="" -# Find the rows and columns -rows=$(tput lines) -columns=$(tput cols) +# Find the rows and columns will default to 80x24 is it can not be detected +screen_size=$(stty size 2>/dev/null || echo 24 80) +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. r=$(( rows / 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 ######## # Must be root to install echo ":::" -if [[ $EUID -eq 0 ]];then +if [[ ${EUID} -eq 0 ]]; then echo "::: You are root." else - echo "::: Script called with non-root privileges. The Pi-hole installs server packages and configures" - echo "::: system networking, it requires elevated rights. Please check the contents of the script for" - echo "::: any concerns with this requirement. Please be sure to download this script from a trusted source." - echo ":::" - echo "::: Detecting the presence of the sudo utility for continuation of this install..." - if [ -x "$(command -v sudo)" ];then + echo "::: Script called with non-root privileges. The Pi-hole installs server packages and configures" + echo "::: system networking, it requires elevated rights. Please check the contents of the script for" + echo "::: any concerns with this requirement. Please be sure to download this script from a trusted source." + echo ":::" + echo "::: Detecting the presence of the sudo utility for continuation of this install..." + + if [ -x "$(command -v sudo)" ]; then echo "::: Utility sudo located." - exec sudo bash "$0" "$@" - exit $? + exec curl -sSL https://install.pi-hole.net | sudo bash "$@" + exit $? 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." exit 1 @@ -63,48 +73,56 @@ fi # Compatibility -if [ -x "$(command -v apt-get)" ];then +if [ -x "$(command -v apt-get)" ]; then #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_CACHE="/var/lib/apt/lists/" - UPDATE_PKG_CACHE="$PKG_MANAGER update" - PKG_UPDATE="$PKG_MANAGER upgrade" - PKG_INSTALL="$PKG_MANAGER --yes --fix-missing install" + UPDATE_PKG_CACHE="${PKG_MANAGER} update" + PKG_UPDATE="${PKG_MANAGER} upgrade" + 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 - 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) - 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_GROUP="www-data" LIGHTTPD_CFG="lighttpd.conf.debian" DNSMASQ_USER="dnsmasq" 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 - if [ -x "$(command -v dnf)" ];then + if [ -x "$(command -v dnf)" ]; then PKG_MANAGER="dnf" else PKG_MANAGER="yum" fi - PKG_CACHE="/var/cache/$PKG_MANAGER" - UPDATE_PKG_CACHE="$PKG_MANAGER check-update" - PKG_UPDATE="$PKG_MANAGER update -y" - PKG_INSTALL="$PKG_MANAGER install -y" - PKG_COUNT="$PKG_MANAGER check-update | grep -v ^Last | grep -c ^[a-zA-Z0-9]" + PKG_CACHE="/var/cache/${PKG_MANAGER}" + UPDATE_PKG_CACHE="${PKG_MANAGER} check-update" + PKG_UPDATE="${PKG_MANAGER} update -y" + PKG_INSTALL="${PKG_MANAGER} install -y" + PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l" 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 ) + if grep -q 'Fedora' /etc/redhat-release; then + remove_deps=(epel-release); + PIHOLE_DEPS=( ${PIHOLE_DEPS[@]/$remove_deps} ); + fi LIGHTTPD_USER="lighttpd" LIGHTTPD_GROUP="lighttpd" LIGHTTPD_CFG="lighttpd.conf.fedora" DNSMASQ_USER="nobody" package_check_install() { - rpm -qa | grep ^"$1"- > /dev/null || ${PKG_INSTALL} "$1" + rpm -qa | grep ^"${1}"- > /dev/null || ${PKG_INSTALL} "${1}" } else echo "OS distribution not supported" @@ -112,19 +130,18 @@ else fi ####### FUNCTIONS ########## -spinner() -{ +spinner() { local pid=$1 - local delay=0.50 - local spinstr='/-\|' - while [ "$(ps a | awk '{print $1}' | grep "$pid")" ]; do + 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" + printf " [%c] " "${spinstr}" + local spinstr=${temp}${spinstr%"$temp"} + sleep ${delay} + printf "\b\b\b\b\b\b" + done + printf " \b\b\b\b" } find_IPv4_information() { @@ -135,7 +152,7 @@ find_IPv4_information() { } get_available_interfaces() { - # Get available interfaces. Consider only getting UP interfaces in the future, and leaving DOWN interfaces out of list. + # Get available interfaces. Consider only getting UP interfaces in the future, and leaving DOWN interfaces out of list. availableInterfaces=$(ip -o link | awk '{print $2}' | grep -v "lo" | cut -d':' -f1 | cut -d'@' -f1) } @@ -162,21 +179,21 @@ verifyFreeDiskSpace() { local existing_free_kilobytes=$(df -Pk | grep -m1 '\/$' | awk '{print $4}') # - Unknown free disk space , not a integer - if ! [[ "$existing_free_kilobytes" =~ ^([0-9])+$ ]]; then - echo "::: Unknown free disk space!" - 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 "::: To do so, pass the argument '--i_do_not_follow_recommendations' to the install script" - echo "::: eg. curl -L https://install.pi-hole.net | bash /dev/stdin --i_do_not_follow_recommendations" - exit 1 + if ! [[ "${existing_free_kilobytes}" =~ ^([0-9])+$ ]]; then + echo "::: Unknown free disk space!" + 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 "::: To do so, pass the argument '--i_do_not_follow_recommendations' to the install script" + echo "::: eg. curl -L https://install.pi-hole.net | bash /dev/stdin --i_do_not_follow_recommendations" + exit 1 # - Insufficient free disk space elif [[ ${existing_free_kilobytes} -lt ${required_free_kilobytes} ]]; then - 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 "::: You only have $existing_free_kilobytes KiloBytes free." - 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 "::: After rebooting, run this installation again. (curl -L https://install.pi-hole.net | bash)" + 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 "::: You only have ${existing_free_kilobytes} KiloBytes free." + 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 "::: After rebooting, run this installation again. (curl -L https://install.pi-hole.net | bash)" echo "Insufficient free space, exiting..." exit 1 @@ -198,23 +215,21 @@ chooseInterface() { # Loop sentinel variable local firstLoop=1 - while read -r line - do + while read -r line; do mode="OFF" if [[ ${firstLoop} -eq 1 ]]; then firstLoop=0 mode="ON" fi - interfacesArray+=("$line" "available" "$mode") - done <<< "$availableInterfaces" + interfacesArray+=("${line}" "available" "${mode}") + done <<< "${availableInterfaces}" # 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}) chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) if [[ $? = 0 ]]; then - for desiredInterface in ${chooseInterfaceOptions} - do + for desiredInterface in ${chooseInterfaceOptions}; do piholeInterface=${desiredInterface} echo "::: Using interface: $piholeInterface" done @@ -248,15 +263,15 @@ use4andor6() { esac done if [[ ${useIPv4} ]]; then - find_IPv4_information - getStaticIPv4Settings - setStaticIPv4 + find_IPv4_information + getStaticIPv4Settings + setStaticIPv4 fi if [[ ${useIPv6} ]]; then - useIPv6dialog - fi - echo "::: IPv4 address: ${IPv4_address}" - echo "::: IPv6 address: ${IPv6_address}" + useIPv6dialog + fi + echo "::: IPv4 address: ${IPv4_address}" + echo "::: IPv6 address: ${IPv6_address}" if [ ! ${useIPv4} ] && [ ! ${useIPv6} ]; then echo "::: Cannot continue, neither IPv4 or IPv6 selected" echo "::: Exiting" @@ -271,8 +286,8 @@ use4andor6() { getStaticIPv4Settings() { # 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? - IP address: $IPv4_address - Gateway: $IPv4gw" ${r} ${c}); then + IP address: ${IPv4_address} + 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. 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. @@ -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. # 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 - until [[ ${ipSettingsCorrect} = True ]] - do + until [[ ${ipSettingsCorrect} = True ]]; do # 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) - if [[ $? = 0 ]];then - echo "::: Your static IPv4 address: $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) + if [[ $? = 0 ]]; then + echo "::: Your static IPv4 address: ${IPv4_address}" # 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) - if [[ $? = 0 ]];then - echo "::: Your static IPv4 gateway: $IPv4gw" + 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 + echo "::: Your static IPv4 gateway: ${IPv4gw}" # 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? - IP address: $IPv4_address - Gateway: $IPv4gw" ${r} ${c}); then + IP address: ${IPv4_address} + Gateway: ${IPv4gw}" ${r} ${c}); then # After that's done, the loop ends and we move on ipSettingsCorrect=True else @@ -321,51 +335,51 @@ It is also possible to use a DHCP reservation, but if you are going to do that, setDHCPCD() { # Append these lines to dhcpcd.conf to enable a static IP - echo "## interface $piholeInterface - static ip_address=$IPv4_address - static routers=$IPv4gw - static domain_name_servers=$IPv4gw" | tee -a /etc/dhcpcd.conf >/dev/null + echo "## interface ${piholeInterface} + static ip_address=${IPv4_address} + static routers=${IPv4gw} + static domain_name_servers=${IPv4gw}" | tee -a /etc/dhcpcd.conf >/dev/null } setStaticIPv4() { - local IFCFG_FILE - local IPADDR - local CIDR - if [[ -f /etc/dhcpcd.conf ]];then + local IFCFG_FILE + local IPADDR + local CIDR + if [[ -f /etc/dhcpcd.conf ]]; then # 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" else setDHCPCD - ip addr replace dev "$piholeInterface" "$IPv4_address" + ip addr replace dev "${piholeInterface}" "${IPv4_address}" 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 ":::" fi elif [[ -f /etc/sysconfig/network-scripts/ifcfg-${piholeInterface} ]];then # Fedora Family 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" else IPADDR=$(echo "${IPv4_address}" | cut -f1 -d/) CIDR=$(echo "${IPv4_address}" | cut -f2 -d/) # 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: { - echo "# Configured via Pi-Hole installer" - echo "DEVICE=$piholeInterface" - echo "BOOTPROTO=none" - echo "ONBOOT=yes" - echo "IPADDR=$IPADDR" - echo "PREFIX=$CIDR" - echo "GATEWAY=$IPv4gw" - echo "DNS1=$piholeDNS1" - echo "DNS2=$piholeDNS2" - echo "USERCTL=no" + echo "# Configured via Pi-Hole installer" + echo "DEVICE=$piholeInterface" + echo "BOOTPROTO=none" + echo "ONBOOT=yes" + echo "IPADDR=$IPADDR" + echo "PREFIX=$CIDR" + echo "GATEWAY=$IPv4gw" + echo "DNS1=$piholeDNS1" + echo "DNS2=$piholeDNS2" + echo "USERCTL=no" }>> "${IFCFG_FILE}" - ip addr replace dev "$piholeInterface" "$IPv4_address" + ip addr replace dev "${piholeInterface}" "${IPv4_address}" if [ -x "$(command -v nmcli)" ];then # Tell NetworkManager to read our new sysconfig file nmcli con load "${IFCFG_FILE}" > /dev/null @@ -380,10 +394,9 @@ setStaticIPv4() { fi } -function valid_ip() -{ - local ip=$1 - local stat=1 +valid_ip() { + local ip=${1} + local stat=1 if [[ ${ip} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then OIFS=$IFS @@ -397,7 +410,7 @@ function valid_ip() return ${stat} } -setDNS(){ +setDNS() { DNSChooseCmd=(whiptail --separate-output --radiolist "Select Upstream DNS Provider. To use your own, select Custom." ${r} ${c} 6) DNSChooseOptions=(Google "" on OpenDNS "" off @@ -408,87 +421,88 @@ setDNS(){ DNSchoices=$("${DNSChooseCmd[@]}" "${DNSChooseOptions[@]}" 2>&1 >/dev/tty) if [[ $? = 0 ]];then case ${DNSchoices} in - Google) - echo "::: Using Google DNS servers." - piholeDNS1="8.8.8.8" - piholeDNS2="8.8.4.4" - ;; - OpenDNS) - echo "::: Using OpenDNS servers." - piholeDNS1="208.67.222.222" - piholeDNS2="208.67.220.220" - ;; - Level3) - echo "::: Using Level3 servers." - piholeDNS1="4.2.2.1" - piholeDNS2="4.2.2.2" - ;; - Norton) - echo "::: Using Norton ConnectSafe servers." - piholeDNS1="199.85.126.10" - piholeDNS2="199.85.127.10" - ;; - Comodo) - echo "::: Using Comodo Secure servers." - piholeDNS1="8.26.56.26" - piholeDNS2="8.20.247.20" - ;; - Custom) - until [[ ${DNSSettingsCorrect} = True ]] - do - strInvalid="Invalid" - if [ ! ${piholeDNS1} ]; then - if [ ! ${piholeDNS2} ]; then - prePopulate="" - else - prePopulate=", $piholeDNS2" - fi - elif [ ${piholeDNS1} ] && [ ! ${piholeDNS2} ]; then - prePopulate="$piholeDNS1" - elif [ ${piholeDNS1} ] && [ ${piholeDNS2} ]; then - prePopulate="$piholeDNS1, $piholeDNS2" - 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 - 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} - fi - if ! valid_ip "$piholeDNS2" && [ "$piholeDNS2" ]; then - piholeDNS2=${strInvalid} - fi - else - echo "::: Cancel selected, exiting...." - exit 1 - fi - 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} - if [[ ${piholeDNS1} == "$strInvalid" ]]; then - piholeDNS1="" - fi - if [[ ${piholeDNS2} == "$strInvalid" ]]; then - piholeDNS2="" - fi - DNSSettingsCorrect=False - 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 - DNSSettingsCorrect=True - else - # If the settings are wrong, the loop continues - DNSSettingsCorrect=False - fi - fi - done - ;; - esac + Google) + echo "::: Using Google DNS servers." + piholeDNS1="8.8.8.8" + piholeDNS2="8.8.4.4" + ;; + OpenDNS) + echo "::: Using OpenDNS servers." + piholeDNS1="208.67.222.222" + piholeDNS2="208.67.220.220" + ;; + Level3) + echo "::: Using Level3 servers." + piholeDNS1="4.2.2.1" + piholeDNS2="4.2.2.2" + ;; + Norton) + echo "::: Using Norton ConnectSafe servers." + piholeDNS1="199.85.126.10" + piholeDNS2="199.85.127.10" + ;; + Comodo) + echo "::: Using Comodo Secure servers." + piholeDNS1="8.26.56.26" + piholeDNS2="8.20.247.20" + ;; + Custom) + until [[ ${DNSSettingsCorrect} = True ]]; do + strInvalid="Invalid" + if [ ! ${piholeDNS1} ]; then + if [ ! ${piholeDNS2} ]; then + prePopulate="" + else + prePopulate=", ${piholeDNS2}" + fi + elif [ ${piholeDNS1} ] && [ ! ${piholeDNS2} ]; then + prePopulate="${piholeDNS1}" + elif [ ${piholeDNS1} ] && [ ${piholeDNS2} ]; then + prePopulate="${piholeDNS1}, ${piholeDNS2}" + 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 + 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} + fi + if ! valid_ip "${piholeDNS2}" && [ "${piholeDNS2}" ]; then + piholeDNS2=${strInvalid} + fi + else + echo "::: Cancel selected, exiting...." + exit 1 + fi + 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} + if [[ ${piholeDNS1} == "${strInvalid}" ]]; then + piholeDNS1="" + fi + if [[ ${piholeDNS2} == "${strInvalid}" ]]; then + piholeDNS2="" + fi + DNSSettingsCorrect=False + 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 + DNSSettingsCorrect=True + else + # If the settings are wrong, the loop continues + DNSSettingsCorrect=False + fi + fi + done + ;; + esac else echo "::: Cancel selected. Exiting..." exit 1 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 local dnsmasq_conf="/etc/dnsmasq.conf" local dnsmasq_conf_orig="/etc/dnsmasq.conf.orig" @@ -520,20 +534,51 @@ version_check_dnsmasq(){ cp ${dnsmasq_pihole_01_snippet} ${dnsmasq_pihole_01_location} echo " done." sed -i "s/@INT@/$piholeInterface/" ${dnsmasq_pihole_01_location} - if [[ "$piholeDNS1" != "" ]]; then + if [[ "${piholeDNS1}" != "" ]]; then sed -i "s/@DNS1@/$piholeDNS1/" ${dnsmasq_pihole_01_location} else sed -i '/^server=@DNS1@/d' ${dnsmasq_pihole_01_location} fi - if [[ "$piholeDNS2" != "" ]]; then + if [[ "${piholeDNS2}" != "" ]]; then sed -i "s/@DNS2@/$piholeDNS2/" ${dnsmasq_pihole_01_location} else sed -i '/^server=@DNS2@/d' ${dnsmasq_pihole_01_location} fi + + #sed -i "s/@HOSTNAME@/$hostname/" ${dnsmasq_pihole_01_location} + + if [[ -f /etc/hostname ]]; then + hostname=$( /dev/null & spinner $! echo " done!" fi } -notify_package_updates_available(){ +notify_package_updates_available() { # Let user know if they have outdated packages on their system and # advise them to run a package update at soonest possible. echo ":::" - echo -n "::: Checking $PKG_MANAGER for upgraded packages...." + echo -n "::: Checking ${PKG_MANAGER} for upgraded packages...." updatesToInstall=$(eval "${PKG_COUNT}") echo " done!" echo ":::" if [[ ${updatesToInstall} -eq "0" ]]; then echo "::: Your system is up to date! Continuing with Pi-hole installation..." else - echo "::: There are $updatesToInstall updates available for your system!" - echo "::: We recommend you run '$PKG_UPDATE' after installing Pi-Hole! " + echo "::: There are ${updatesToInstall} updates available for your system!" + echo "::: We recommend you run '${PKG_UPDATE}' after installing Pi-Hole! " echo ":::" fi } -install_dependent_packages(){ - # Install packages passed in via argument array - # No spinner - conflicts with set -e - declare -a argArray1=("${!1}") +install_dependent_packages() { + # Install packages passed in via argument array + # No spinner - conflicts with set -e + declare -a argArray1=("${!1}") for i in "${argArray1[@]}"; do echo -n "::: Checking for $i..." @@ -671,36 +721,37 @@ getGitFiles() { update_repo "${1}" else make_repo "${1}" "${2}" - fi + fi } is_repo() { - # Use git to check if directory is currently under VCS + # 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!" + # 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 pull -q > /dev/null & spinner $! - echo " done!" + # 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!" } CreateLogFile() { # Create logfiles if necessary echo ":::" - echo -n "::: Creating log file and changing owner to dnsmasq..." + echo -n "::: Creating log file and changing owner to dnsmasq..." if [ ! -f /var/log/pihole.log ]; then touch /var/log/pihole.log chmod 644 /var/log/pihole.log @@ -755,7 +806,7 @@ runGravity() { /opt/pihole/gravity.sh } -create_pihole_user(){ +create_pihole_user() { # Check if user pihole exists and create if not 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) @@ -777,20 +828,19 @@ configureFirewall() { } finalExports() { - #If it already exists, lets overwrite it with the new values. - if [[ -f ${setupVars} ]];then - rm ${setupVars} - fi + #If it already exists, lets overwrite it with the new values. + if [[ -f ${setupVars} ]]; then + rm ${setupVars} + fi { - echo "piholeInterface=${piholeInterface}" - echo "IPv4_address=${IPv4_address}" - echo "IPv6_address=${IPv6_address}" - echo "piholeDNS1=${piholeDNS1}" - echo "piholeDNS2=${piholeDNS2}" + echo "piholeInterface=${piholeInterface}" + echo "IPv4_address=${IPv4_address}" + echo "IPv6_address=${IPv6_address}" + echo "piholeDNS1=${piholeDNS1}" + echo "piholeDNS2=${piholeDNS2}" }>> "${setupVars}" } - installPihole() { # Install base files and web interface create_pihole_user @@ -817,6 +867,11 @@ installPihole() { } 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 installScripts installConfigs @@ -834,9 +889,12 @@ configureSelinux() { printf ":::\tChecking for SELinux policy development packages..." package_check_install "selinux-policy-devel" > /dev/null 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" 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 semodule_package -o /etc/pihole/pihole.pp -m /etc/pihole/pihole.mod 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: IPv4: ${IPv4_address%/*} -IPv6: $IPv6_address +IPv6: ${IPv6_address} If you set a new IP address, you should restart the Pi. @@ -858,24 +916,35 @@ The install log is in /etc/pihole. 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 \ - "Update" "Update install will retain existing settings." \ - "Install" "Install will allow you to enter new settings." 3>&2 2>&1 1>&3) + 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 \ + "${opt1a}" "${opt1b}" \ + "${opt2a}" "${opt2b}" 3>&2 2>&1 1>&3) - if [[ $? = 0 ]];then + if [[ $? = 0 ]];then case ${UpdateCmd} in - Update) - echo "::: Updating existing install" - . ${setupVars} - useUpdateVars=true - ;; - Install) - echo "::: Running complete install script" - useUpdateVars=false - ;; - esac + ${opt1a}) + echo "::: ${opt1a} option selected." + useUpdateVars=true + ;; + ${opt2a}) + echo "::: ${opt2a} option selected" + useUpdateVars=false + ;; + esac else echo "::: Cancel selected. Exiting..." exit 1 @@ -884,91 +953,105 @@ update_dialogs(){ } main() { -if [[ -f ${setupVars} ]];then - if [ "$1" == "pihole" ]; then - useUpdateVars=true - else - update_dialogs - fi -fi +# Check arguments for the undocumented flags + for var in "$@"; do + case "$var" in + "--reconfigure" ) reconfigure=true;; + "--i_do_not_follow_recommendations" ) skipSpaceCheck=false;; + "--unattended" ) runUnattended=true;; + esac + done -# Start the installer -# Verify there is enough disk space for the install -if [[ $1 = "--i_do_not_follow_recommendations" ]]; then - echo "::: --i_do_not_follow_recommendations passed to script" - echo "::: skipping free disk space verification!" -else - verifyFreeDiskSpace -fi + if [[ -f ${setupVars} ]]; then + if [[ "${runUnattended}" == true ]]; then + echo "::: --unattended passed to install script, no whiptail dialogs will be displayed" + useUpdateVars=true + else + update_dialogs + fi + fi -# Update package cache -update_pacakge_cache + # Start the installer + # Verify there is enough disk space for the install + if [[ "${skipSpaceCheck}" == true ]]; then + echo "::: --i_do_not_follow_recommendations passed to script, skipping free disk space verification!" + else + verifyFreeDiskSpace + fi -# Notify user of package availability -notify_package_updates_available + # Update package cache + update_pacakge_cache -# Install packages used by this installation script -install_dependent_packages INSTALLER_DEPS[@] + # Notify user of package availability + notify_package_updates_available -# Install packages used by the Pi-hole -install_dependent_packages PIHOLE_DEPS[@] + # Install packages used by this installation script + install_dependent_packages INSTALLER_DEPS[@] -if [[ ${useUpdateVars} == false ]]; then - # Display welcome dialogs - welcomeDialogs - # Create directory for Pi-hole storage - mkdir -p /etc/pihole/ - # Remove legacy scripts from previous storage location - remove_legacy_scripts - # Get Git files for Core and Admin - getGitFiles ${piholeFilesDir} ${piholeGitUrl} - getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl} - # Stop resolver and webserver while installing proceses - stop_service dnsmasq - stop_service lighttpd - # Determine available interfaces - get_available_interfaces - # Find interfaces and let the user choose one - chooseInterface - # Let the user decide if they want to block ads over IPv4 and/or IPv6 - use4andor6 - # Decide what upstream DNS Servers to use - setDNS - # Install and log everything to a file - installPihole | tee ${tmpLog} -else - updatePihole | tee ${tmpLog} -fi + # Install packages used by the Pi-hole + install_dependent_packages PIHOLE_DEPS[@] -# Move the log file into /etc/pihole for storage -mv ${tmpLog} ${instalLogLoc} + if [[ "${reconfigure}" == true ]]; then + 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 - displayFinalMessage -fi + if [[ ${useUpdateVars} == false ]]; then + # Display welcome dialogs + welcomeDialogs + # Create directory for Pi-hole storage + mkdir -p /etc/pihole/ + # Remove legacy scripts from previous storage location + remove_legacy_scripts + # Stop resolver and webserver while installing proceses + stop_service dnsmasq + stop_service lighttpd + # Determine available interfaces + get_available_interfaces + # Find interfaces and let the user choose one + chooseInterface + # Let the user decide if they want to block ads over IPv4 and/or IPv6 + use4andor6 + # Decide what upstream DNS Servers to use + setDNS + # Install and log everything to a file + installPihole | tee ${tmpLog} + else + updatePihole | tee ${tmpLog} + fi -echo -n "::: Restarting services..." -# Start services -start_service dnsmasq -enable_service dnsmasq -start_service lighttpd -enable_service lighttpd -echo " done." + # Move the log file into /etc/pihole for storage + mv ${tmpLog} ${instalLogLoc} -echo ":::" -if [[ ${useUpdateVars} == false ]]; then - echo "::: Installation Complete! Configure your devices to use the Pi-hole as their DNS server using:" - echo "::: ${IPv4_address%/*}" - echo "::: $IPv6_address" - echo ":::" - echo "::: If you set a new IP address, you should restart the Pi." -else - echo "::: Update complete!" -fi + if [[ "${useUpdateVars}" == false ]]; then + displayFinalMessage + fi -echo ":::" -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 "::: Restarting services..." + # Start services + start_service dnsmasq + enable_service dnsmasq + start_service lighttpd + enable_service lighttpd + echo "::: done." + + echo ":::" + if [[ "${useUpdateVars}" == false ]]; then + echo "::: Installation Complete! Configure your devices to use the Pi-hole as their DNS server using:" + echo "::: ${IPv4_address%/*}" + echo "::: ${IPv6_address}" + echo ":::" + echo "::: If you set a new IP address, you should restart the Pi." + else + echo "::: Update complete!" + fi + + echo ":::" + 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" } if [[ -z "$PHTEST" ]] ; then diff --git a/automated install/uninstall.sh b/automated install/uninstall.sh index 01e76cad..abba88a5 100755 --- a/automated install/uninstall.sh +++ b/automated install/uninstall.sh @@ -11,29 +11,29 @@ # (at your option) any later version. # Must be root to uninstall -if [[ $EUID -eq 0 ]];then +if [[ ${EUID} -eq 0 ]]; then echo "::: You are root." else echo "::: Sudo will be used for the uninstall." - # Check if it is actually installed - # If it isn't, exit because the unnstall cannot complete - if [ -x "$(command -v sudo)" ];then + # Check if it is actually installed + # If it isn't, exit because the unnstall cannot complete + if [ -x "$(command -v sudo)" ]; then export SUDO="sudo" - else - echo "::: Please install sudo or run this as root." - exit 1 - fi + else + echo "::: Please install sudo or run this as root." + exit 1 + fi fi # Compatability -if [ -x "$(command -v rpm)" ];then +if [ -x "$(command -v rpm)" ]; then # Fedora Family - if [ -x "$(command -v dnf)" ];then + if [ -x "$(command -v dnf)" ]; then PKG_MANAGER="dnf" else PKG_MANAGER="yum" 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 ) package_check() { rpm -qa | grep ^$1- > /dev/null @@ -41,10 +41,10 @@ if [ -x "$(command -v rpm)" ];then package_cleanup() { ${SUDO} ${PKG_MANAGER} -y autoremove } -elif [ -x "$(command -v apt-get)" ];then +elif [ -x "$(command -v apt-get)" ]; then # Debian Family 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 ) package_check() { dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -c "ok installed" @@ -58,37 +58,36 @@ else exit fi -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" +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" } -function removeAndPurge { +removeAndPurge() { # Purge dependencies -echo ":::" + echo ":::" for i in "${PIHOLE_DEPS[@]}"; do package_check ${i} > /dev/null if [ $? -eq 0 ]; then 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 - [Yy]* ) printf ":::\tRemoving %s..." "$i"; ${SUDO} ${PKG_REMOVE} "$i" &> /dev/null & spinner $!; printf "done!\n"; break;; - [Nn]* ) printf ":::\tSkipping %s" "$i\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;; * ) printf "::: You must answer yes or no!\n";; esac done else - printf ":::\tPackage %s not installed... Not removing.\n" "$i" + printf ":::\tPackage %s not installed... Not removing.\n" "${i}" fi done @@ -104,7 +103,7 @@ echo ":::" removeNoPurge } -function removeNoPurge { +removeNoPurge() { echo ":::" # Only web directories/files that are created by pihole should be removed. echo "::: Removing the Pi-hole Web server files..." diff --git a/gravity.sh b/gravity.sh index bcfcc9ee..112b42b6 100755 --- a/gravity.sh +++ b/gravity.sh @@ -13,42 +13,38 @@ # 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 - -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" +helpFunc() { + cat << EOM +::: Pull in domains from adlists +::: +::: Usage: pihole -g +::: +::: Options: +::: -f, --force Force lists to be downloaded, even if they don't need updating. +::: -h, --help Show this help dialog +EOM exit 1 } adListFile=/etc/pihole/adlists.list adListDefault=/etc/pihole/adlists.default -whitelistScript=/opt/pihole/whitelist.sh -blacklistScript=/opt/pihole/blacklist.sh +whitelistScript="pihole -w" +whitelistFile=/etc/pihole/whitelist.txt +blacklistFile=/etc/pihole/blacklist.txt #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. -IPv4addr=${IPv4_address%/*} +IPv4_address=${IPv4_address%/*} # Variables for various stages of downloading and formatting the list basename=pihole @@ -57,18 +53,20 @@ adList=${piholeDir}/gravity.list justDomainsExtension=domains matterAndLight=${basename}.0.matterandlight.txt supernova=${basename}.1.supernova.txt -eventHorizon=${basename}.2.eventHorizon.txt +preEventHorizon=list.preEventHorizon +eventHorizon=${basename}.2.supernova.txt accretionDisc=${basename}.3.accretionDisc.txt -# After setting defaults, check if there's local overrides -if [[ -r ${piholeDir}/pihole.conf ]];then - echo "::: Local calibration requested..." - . ${piholeDir}/pihole.conf +skipDownload=false + +# Warn users still using pihole.conf that it no longer has any effect (I imagine about 2 people use it) +if [[ -r ${piholeDir}/pihole.conf ]]; then + echo "::: pihole.conf file no longer supported. Over-rides in this file are ignored." fi ########################### # collapse - begin formation of pihole -function gravity_collapse() { +gravity_collapse() { echo "::: Neutrino emissions detected..." echo ":::" #Decide if we're using a custom ad block list, or defaults. @@ -99,31 +97,17 @@ function gravity_collapse() { done < ${adListDefault} echo " done!" 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. -function gravity_patternCheck() { +gravity_patternCheck() { patternBuffer=$1 # 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 # and stored as is. They can be processed for content after they # have been saved. - cp "$patternBuffer" "$saveLocation" + mv "${patternBuffer}" "${saveLocation}" echo " List updated, transport successful!" else # 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 -function gravity_transport() { +gravity_transport() { url=$1 cmd_ext=$2 agent=$3 @@ -142,148 +126,160 @@ function gravity_transport() { heisenbergCompensator="" if [[ -r ${saveLocation} ]]; then # if domain has been saved, add file for date check to only download newer - heisenbergCompensator="-z $saveLocation" + heisenbergCompensator="-z ${saveLocation}" fi # 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 - gravity_patternCheck "$patternBuffer" - # Cleanup - rm -f "$patternBuffer" + gravity_patternCheck "${patternBuffer}" } # spinup - main gravity function -function gravity_spinup() { +gravity_spinup() { echo ":::" # Loop through domain list. Download each one and remove commented lines (lines beginning with '# 'or '/') and # blank lines - for ((i = 0; i < "${#sources[@]}"; i++)) - do - url=${sources[$i]} - # Get just the domain from the URL - domain=$(echo "$url" | cut -d'/' -f3) + for ((i = 0; i < "${#sources[@]}"; i++)); do + url=${sources[$i]} + # Get just the domain from the URL + domain=$(echo "${url}" | cut -d'/' -f3) - # Save the file as list.#.domain - saveLocation=${piholeDir}/list.${i}.${domain}.${justDomainsExtension} - activeDomains[$i]=${saveLocation} + # Save the file as list.#.domain + saveLocation=${piholeDir}/list.${i}.${domain}.${justDomainsExtension} + activeDomains[$i]=${saveLocation} - 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 + # to complete properly and reset the user agent when required + case "${domain}" in + "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' + cmd_ext="-e http://forum.xda-developers.com/" + ;; - # Use a case statement to download lists that need special cURL commands - # to complete properly and reset the user agent when required - case "$domain" in - "adblock.mahakala.is") - agent='Mozilla/5.0 (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/" - ;; - - "pgl.yoyo.org") - cmd_ext="-d mimetype=plaintext -d hostformat=hosts" - ;; + "pgl.yoyo.org") + cmd_ext="-d mimetype=plaintext -d hostformat=hosts" + ;; # Default is a simple request *) cmd_ext="" esac - gravity_transport "$url" "$cmd_ext" "$agent" + if [[ "${skipDownload}" == false ]]; then + echo -n "::: Getting $domain list..." + gravity_transport "$url" "$cmd_ext" "$agent" + fi done } # Schwarzchild - aggregate domains to one list and add blacklisted domains -function gravity_Schwarzchild() { +gravity_Schwarzchild() { echo "::: " # Find all active domains and compile them into one file and remove CRs echo -n "::: Aggregating list of domains..." truncate -s 0 ${piholeDir}/${matterAndLight} - for i in "${activeDomains[@]}" - do - cat "$i" | tr -d '\r' >> ${piholeDir}/${matterAndLight} + for i in "${activeDomains[@]}"; do + cat "${i}" | tr -d '\r' >> ${piholeDir}/${matterAndLight} done echo " done!" } -function gravity_Blacklist(){ - # Append blacklist entries if they exist - echo -n "::: Running blacklist script to update HOSTS file...." - ${blacklistScript} -f -nr -q > /dev/null +gravity_Blacklist() { + # Append blacklist entries to eventHorizon if they exist + if [[ -f "${blacklistFile}" ]]; then + numBlacklisted=$(wc -l < "${blacklistFile}") + plural=; [[ "$numBlacklisted" != "1" ]] && plural=s + echo -n "::: BlackListing $numBlacklisted domain${plural}..." + cat ${blacklistFile} >> ${piholeDir}/${eventHorizon} + echo " done!" + else + echo "::: Nothing to blacklist!" + fi - numBlacklisted=$(wc -l < "/etc/pihole/blacklist.txt") - plural=; [[ "$numBlacklisted" != "1" ]] && plural=s - echo " $numBlacklisted domain${plural} blacklisted!" } -function gravity_Whitelist() { +gravity_Whitelist() { + #${piholeDir}/${eventHorizon}) echo ":::" # Prevent our sources from being pulled into the hole plural=; [[ "${sources[@]}" != "1" ]] && plural=s - echo -n "::: Adding ${#sources[@]} adlist source${plural} to the whitelist..." + echo -n "::: Adding adlist source${plural} to the whitelist..." urls=() - for url in "${sources[@]}" - do - tmp=$(echo "$url" | awk -F '/' '{print $3}') - urls=("${urls[@]}" ${tmp}) + for url in "${sources[@]}"; do + tmp=$(echo "${url}" | awk -F '/' '{print $3}') + urls=("${urls[@]}" ${tmp}) done echo " done!" - echo -n "::: Running whitelist script to update HOSTS file...." - ${whitelistScript} -f -nr -q "${urls[@]}" > /dev/null - numWhitelisted=$(wc -l < "/etc/pihole/whitelist.txt") - plural=; [[ "$numWhitelisted" != "1" ]] && plural=s - echo " $numWhitelisted domain${plural} whitelisted!" + # Ensure adlist domains are in whitelist.txt + ${whitelistScript} -nr -q "${urls[@]}" > /dev/null + + # 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 + 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 echo -n "::: Removing duplicate domains...." - sort -u ${piholeDir}/${supernova} > ${piholeDir}/${eventHorizon} + sort -u ${piholeDir}/${supernova} > ${piholeDir}/${preEventHorizon} echo " done!" - numberOf=$(wc -l < ${piholeDir}/${eventHorizon}) + numberOf=$(wc -l < ${piholeDir}/${preEventHorizon}) echo "::: $numberOf unique domains trapped in the event horizon." } -function gravity_hostFormat() { +gravity_hostFormat() { # Format domain list as "192.168.x.x domain.com" echo "::: Formatting domains into a HOSTS file..." - if [[ -f /etc/hostname ]]; then - hostname=$( ${piholeDir}/${accretionDisc} - cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPv4addr" -v ipv6addr="$IPv6_address" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> ${piholeDir}/${accretionDisc} - else - # Otherwise, just create gravity.list as normal using IPv4 - # Add hostname and dummy domain to the top of gravity.list to make ping result return a friendlier looking domain! Also allows for an easy way to access the Pi-hole admin console (pi.hole/admin) - echo -e "$IPv4addr $hostname\n$IPv4addr pi.hole" > ${piholeDir}/${accretionDisc} - cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPv4addr" '{sub(/\r$/,""); print ipv4addr" "$0}' >> ${piholeDir}/${accretionDisc} - fi + # Check vars from setupVars.conf to see if we're using IPv4, IPv6, Or both. + if [[ -n "${IPv4_address}" && -n "${IPv6_address}" ]];then + + # Both IPv4 and IPv6 + cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPv4_address" -v ipv6addr="$IPv6_address" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> ${piholeDir}/${accretionDisc} + + elif [[ -n "${IPv4_address}" && -z "${IPv6_address}" ]];then + + # Only IPv4 + cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPv4_address" '{sub(/\r$/,""); print ipv4addr" "$0}' >> ${piholeDir}/${accretionDisc} + + elif [[ -z "${IPv4_address}" && -n "${IPv6_address}" ]];then + + # Only IPv6 + cat ${piholeDir}/${eventHorizon} | awk -v ipv6addr="$IPv6_address" '{sub(/\r$/,""); print ipv6addr" "$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 # Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it cp ${piholeDir}/${accretionDisc} ${adList} } # blackbody - remove any remnant files from script processes -function gravity_blackbody() { +gravity_blackbody() { # Loop through list files - for file in ${piholeDir}/*.${justDomainsExtension} - do + for file in ${piholeDir}/*.${justDomainsExtension}; do # If list is in active array then leave it (noop) else rm the list if [[ " ${activeDomains[@]} " =~ ${file} ]]; then : else - rm -f "$file" + rm -f "${file}" fi done } -function gravity_advanced() { +gravity_advanced() { # Remove comments and print only the domain name # Most of the lists downloaded are already in hosts file format but the spacing/formating is not contigious # This helps with that and makes it easier to read @@ -296,64 +292,62 @@ function gravity_advanced() { echo " done!" numberOf=$(wc -l < ${piholeDir}/${supernova}) - echo "::: $numberOf domains being pulled in by gravity..." + echo "::: ${numberOf} domains being pulled in by gravity..." gravity_unique } -function gravity_reload() { +gravity_reload() { #Clear no longer needed files... echo ":::" echo -n "::: Cleaning up un-needed files..." - ${SUDO} rm ${piholeDir}/pihole.*.txt + rm ${piholeDir}/pihole.*.txt echo " done!" # Reload hosts file 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! #First escape forward slashes in the path: adList=${adList//\//\\\/} #Now replace the line in dnsmasq file - ${SUDO} sed -i "s/^addn-hosts.*/addn-hosts=$adList/" /etc/dnsmasq.d/01-pihole.conf - dnsmasqPid=$(pidof dnsmasq) +# sed -i "s/^addn-hosts.*/addn-hosts=$adList/" /etc/dnsmasq.d/01-pihole.conf - find "$piholeDir" -type f -exec ${SUDO} chmod 666 {} \; - - if [[ ${dnsmasqPid} ]]; then - # service already running - reload config - ${SUDO} killall -s HUP dnsmasq - else - # service not running, start it up - ${SUDO} service dnsmasq start - fi - echo " done!" + pihole restartdns } - -for var in "$@" -do - case "$var" in - "-f" | "--force" ) forceGrav=true;; - "-h" | "--help" ) helpFunc;; - esac +for var in "$@"; do + case "${var}" in + "-f" | "--force" ) forceGrav=true;; + "-h" | "--help" ) helpFunc;; + "-sd" | "--skip-download" ) skipDownload=true;; + esac done -if [[ ${forceGrav} == true ]]; then +if [[ "${forceGrav}" == true ]]; then echo -n "::: Deleting exising list cache..." - ${SUDO} rm /etc/pihole/list.* + rm /etc/pihole/list.* echo " done!" fi #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_spinup -gravity_Schwarzchild -gravity_advanced -gravity_hostFormat -gravity_blackbody +if [[ "${skipDownload}" == false ]]; then + gravity_Schwarzchild + gravity_advanced +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_Blacklist + +gravity_hostFormat +gravity_blackbody + gravity_reload +pihole status diff --git a/pihole b/pihole index e0d1715a..4b197d12 100755 --- a/pihole +++ b/pihole @@ -12,190 +12,198 @@ # Must be root to use this tool if [[ ! $EUID -eq 0 ]];then - #echo "::: You are root." -#else - #echo "::: Sudo will be used for this tool." - # Check if it is actually installed - # If it isn't, exit because the pihole cannot be invoked without privileges. - if [ -x "$(command -v sudo)" ];then - export SUDO="sudo" - else - echo "::: Please install sudo or run this as root." - exit 1 - fi + if [ -x "$(command -v sudo)" ];then + exec sudo bash "$0" "$@" + exit $? + else + echo "::: sudo is needed to run pihole commands. Please run this script as root or install sudo." + exit 1 + fi fi -function whitelistFunc { - shift - ${SUDO} /opt/pihole/whitelist.sh "$@" - exit 1 +whitelistFunc() { + /opt/pihole/list.sh "$@" + exit 0 } -function blacklistFunc { - shift - ${SUDO} /opt/pihole/blacklist.sh "$@" - exit 1 +blacklistFunc() { + /opt/pihole/list.sh "$@" + exit 0 } -function debugFunc { - ${SUDO} /opt/pihole/piholeDebug.sh - exit 1 +debugFunc() { + /opt/pihole/piholeDebug.sh + exit 0 } -function flushFunc { - ${SUDO} /opt/pihole/piholeLogFlush.sh - exit 1 +flushFunc() { + /opt/pihole/piholeLogFlush.sh + exit 0 } -function updatePiholeFunc { +updatePiholeFunc() { + /opt/pihole/update.sh + exit 0 +} - 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 +reconfigurePiholeFunc() { + /etc/.pihole/automated\ install/basic-install.sh --reconfigure + exit 0; +} - 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/",$//') +updateGravityFunc() { + /opt/pihole/gravity.sh "$@" + exit 0 +} - 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/",$//') +setupLCDFunction() { + /opt/pihole/setupLCD.sh + exit 0 +} - echo "::: Pi-hole version is $piholeVersion (Latest version is $piholeVersionLatest)" - echo "::: Web Admin version is $webVersion (Latest version is $webVersionLatest)" - echo ":::" +queryFunc() { + domain=$2 + for list in /etc/pihole/list.*; do + count=$(grep ${domain} $list | wc -l) + echo "::: ${list} (${count} results)" + if [[ ${count} > 0 ]]; then + grep ${domain} ${list} + fi + echo "" + done + exit 0 +} - if [[ ${piholeVersion} == ${piholeVersionLatest} ]] ; then - echo "::: Pi-hole Base files are already up to date! Version: ${piholeVersionLatest}" - echo "::: No need to update!" - echo ":::" +chronometerFunc() { + shift + /opt/pihole/chronometer.sh "$@" + exit 0 +} - 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 + +uninstallFunc() { + /opt/pihole/uninstall.sh + exit 0 +} + +versionFunc() { + shift + /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 - 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" + service dnsmasq restart fi - - exit 1 + else + # service not running, start it up + if [ -x "$(command -v systemctl)" ]; then + systemctl start dnsmasq + else + service dnsmasq start + fi + fi } -function updateGravityFunc { - ${SUDO} /opt/pihole/gravity.sh "$@" - exit 1 +piholeEnable() { + if [[ "${1}" == "0" ]] ; then + #Disable Pihole + sed -i 's/^addn-hosts/#addn-hosts/' /etc/dnsmasq.d/01-pihole.conf + echo "::: Blocking has been disabled!" + else + #Enable pihole + echo "::: Blocking has been enabled!" + sed -i 's/^#addn-hosts/addn-hosts/' /etc/dnsmasq.d/01-pihole.conf + fi + restartDNS } -function setupLCDFunction { - ${SUDO} /opt/pihole/setupLCD.sh - exit 1 -} - -function queryFunc { - domain=$2 - for list in /etc/pihole/list.* - do - count=$(grep ${domain} $list | wc -l) - echo "::: ${list} (${count} results)" - if [[ ${count} > 0 ]]; then - grep ${domain} ${list} - fi - echo "" - done - exit 1 -} - -function chronometerFunc { - shift - ${SUDO} /opt/pihole/chronometer.sh "$@" - exit 1 +piholeStatus() { + if [[ $(cat /etc/dnsmasq.d/01-pihole.conf | grep "#addn-hosts=/") ]] ; then + #list is commented out + if [[ "${1}" == "web" ]] ; then + echo 0; + 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 } -function uninstallFunc { - ${SUDO} /opt/pihole/uninstall.sh - exit 1 -} - -function versionFunc { - ${SUDO} /opt/pihole/version.sh - exit 1 -} - -function helpFunc { - echo "::: Control all PiHole specific functions!" - echo ":::" - echo "::: Usage: pihole [options]" - echo "::: Add -h after -w (whitelist), -b (blacklist), or -c (chronometer) for more information on usage" - echo ":::" - echo "::: Options:" - echo "::: -w, whitelist Whitelist domains" - echo "::: -b, blacklist Blacklist domains" - echo "::: -d, debug Start a debugging session if having trouble" - echo "::: -f, flush Flush the pihole.log file" - echo "::: -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" - echo "::: -c, chronometer Calculates stats and displays to an LCD" - echo "::: -h, help Show this help dialog" - echo "::: -v, version Show current versions" - echo "::: -q, query Query the adlists for a specific domain" - echo "::: uninstall Uninstall Pi-Hole from your system :(!" - exit 1 +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 } if [[ $# = 0 ]]; then - helpFunc + helpFunc fi # Handle redirecting to specific functions based on arguments -case "$1" in -"-w" | "whitelist" ) whitelistFunc "$@";; -"-b" | "blacklist" ) blacklistFunc "$@";; -"-d" | "debug" ) debugFunc;; -"-f" | "flush" ) flushFunc;; -"-up" | "updatePihole" ) updatePiholeFunc;; -"-g" | "updateGravity" ) updateGravityFunc "$@";; -"-s" | "setupLCD" ) setupLCDFunction;; -"-c" | "chronometer" ) chronometerFunc "$@";; -"-h" | "help" ) helpFunc;; -"-v" | "version" ) versionFunc;; -"-q" | "query" ) queryFunc "$@";; -"uninstall" ) uninstallFunc;; -* ) helpFunc;; +case "${1}" in + "-w" | "whitelist" ) whitelistFunc "$@";; + "-b" | "blacklist" ) blacklistFunc "$@";; + "-d" | "debug" ) debugFunc;; + "-f" | "flush" ) flushFunc;; + "-up" | "updatePihole" ) updatePiholeFunc;; + "-r" | "reconfigure" ) reconfigurePiholeFunc;; + "-g" | "updateGravity" ) updateGravityFunc "$@";; + "-s" | "setupLCD" ) setupLCDFunction;; + "-c" | "chronometer" ) chronometerFunc "$@";; + "-h" | "help" ) helpFunc;; + "-v" | "version" ) versionFunc "$@";; + "-q" | "query" ) queryFunc "$@";; + "uninstall" ) uninstallFunc;; + "enable" ) piholeEnable 1;; + "disable" ) piholeEnable 0;; + "status" ) piholeStatus "$2";; + "restartdns" ) restartDNS;; + * ) helpFunc;; esac