From ae30c285a23240211c4641832cec42905e5be328 Mon Sep 17 00:00:00 2001 From: Markus Napp Date: Sun, 12 Mar 2017 15:45:11 +0100 Subject: [PATCH 001/162] Fix handling of wildcard help text --- advanced/Scripts/list.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh index 2ac1e805..a094becb 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -31,13 +31,16 @@ helpFunc() { if [[ ${listMain} == ${whitelist} ]]; then letter="w" word="white" + elif [[ ${listMain} == ${wildcardlist} ]]; then + letter="wild" + word="wildcard" else letter="b" word="black" fi cat << EOM -::: Immediately ${word}lists one or more domains in the hosts file +::: Immediately add one or more domains to the ${word}list ::: ::: Usage: pihole -${letter} domain1 [domain2 ...] ::: @@ -48,7 +51,7 @@ helpFunc() { ::: -h, --help Show this help dialog ::: -l, --list Display your ${word}listed domains EOM -if [[ "${letter}" == "b" ]]; then +if [[ "${letter}" == "-wild" ]]; then echo "::: -wild, --wildcard Add wildcard entry (only blacklist)" fi exit 0 From 9a475cc0107c263e814a17acd676a3f8f7ef68e1 Mon Sep 17 00:00:00 2001 From: Markus Napp Date: Sun, 12 Mar 2017 15:50:48 +0100 Subject: [PATCH 002/162] Rewrite help text for better handling of params --- advanced/Scripts/list.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh index a094becb..a4611a4a 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -49,9 +49,9 @@ helpFunc() { ::: -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 +::: -l, --list Display domains on the ${word}list EOM -if [[ "${letter}" == "-wild" ]]; then +if [[ "${letter}" == "wild" ]]; then echo "::: -wild, --wildcard Add wildcard entry (only blacklist)" fi exit 0 From bb7a7d94efe54b27e9e58af6c42314b6c45e4723 Mon Sep 17 00:00:00 2001 From: Markus Napp Date: Sun, 12 Mar 2017 16:16:45 +0100 Subject: [PATCH 003/162] Replace misleading letter variable --- advanced/Scripts/list.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh index a4611a4a..8eb0543d 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -29,20 +29,20 @@ listAlt="" helpFunc() { if [[ ${listMain} == ${whitelist} ]]; then - letter="w" + param="w" word="white" elif [[ ${listMain} == ${wildcardlist} ]]; then - letter="wild" + param="wild" word="wildcard" else - letter="b" + param="b" word="black" fi cat << EOM ::: Immediately add one or more domains to the ${word}list ::: -::: Usage: pihole -${letter} domain1 [domain2 ...] +::: Usage: pihole -${param} domain1 [domain2 ...] ::: ::: Options: ::: -d, --delmode Remove domains from the ${word}list @@ -51,7 +51,7 @@ helpFunc() { ::: -h, --help Show this help dialog ::: -l, --list Display domains on the ${word}list EOM -if [[ "${letter}" == "wild" ]]; then +if [[ "${param}" == "wild" ]]; then echo "::: -wild, --wildcard Add wildcard entry (only blacklist)" fi exit 0 From 7abf3497304075ceafdc370429dada01ea81dfae Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 13 May 2017 21:08:21 +0200 Subject: [PATCH 004/162] Use `echo "ABC" | pihole tricorder` to upload to Pi-hole's medical tricorder. Uses SSL if available. --- pihole | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pihole b/pihole index 4fafe27a..f24461d3 100755 --- a/pihole +++ b/pihole @@ -94,7 +94,7 @@ scanList(){ queryFunc() { method="${3}" - + # If domain contains non ASCII characters, convert domain to punycode if python exists # Cr: https://serverfault.com/a/335079 if [ -z "${2}" ]; then @@ -105,7 +105,7 @@ queryFunc() { else domain="${2}" fi - + # Scan Whitelist, Blacklist and Wildcards lists="/etc/pihole/whitelist.txt /etc/pihole/blacklist.txt $wildcardlist" result=$(scanList ${domain} "${lists}" ${method}) @@ -122,7 +122,7 @@ queryFunc() { [ -n "$method" ] && exact="exact " echo "::: No ${exact}results found for ${domain}" fi - + exit 0 } @@ -268,6 +268,14 @@ piholeCheckoutFunc() { checkout "$@" } +tricorderFunc() { + if command -v openssl &> /dev/null; then + openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin + else + nc tricorder.pi-hole.net 9999 < /dev/stdin + fi +} + helpFunc() { cat << EOM ::: Control all Pi-hole specific functions @@ -302,6 +310,7 @@ helpFunc() { ::: 'pihole disable 5m' - will disable blocking for 5 minutes ::: restartdns Restart dnsmasq ::: checkout Check out different branches +::: tricorder Upload log to Pi-hole's medical tricorder (uses SSL when possible) EOM exit 0 } @@ -333,5 +342,6 @@ case "${1}" in "-a" | "admin" ) webpageFunc "$@";; "-t" | "tail" ) tailFunc;; "checkout" ) piholeCheckoutFunc "$@";; + "tricorder" ) tricorderFunc;; * ) helpFunc;; esac From 55f78e3b64470f82e088ecc714187ac5dd972456 Mon Sep 17 00:00:00 2001 From: Adam Hill Date: Sat, 13 May 2017 18:44:41 -0500 Subject: [PATCH 005/162] Update list.sh I believe this has feature parity with `sed /foo/ Id` but also supports busybox, and my alpine docker ;) --- advanced/Scripts/list.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh index 537ebac3..52c4c569 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -157,8 +157,8 @@ RemoveDomain() { if [[ "${bool}" == true ]]; then # Remove it from the other one echo "::: Removing $1 from $list..." - # /I flag: search case-insensitive - sed -i "/${domain}/Id" "${list}" + # Busybox sed compatible case-insensitive domain removal + sed -i "$(grep -in "^${domain}$" ${list} | awk -F':' '{print $1}' | tr '\n' ',' | sed 's/,$/\n/')d" ${list} reload=true else if [[ "${verbose}" == true ]]; then @@ -174,8 +174,8 @@ RemoveDomain() { if [[ "${bool}" == true ]]; then # Remove it from the other one echo "::: Removing $1 from $list..." - # /I flag: search case-insensitive - sed -i "/address=\/${domain}/Id" "${list}" + # Busybox sed compatible case-insensitive domain removal + sed -i "$(grep -in "/${domain}/" ${list} | awk -F':' '{print $1}' | tr '\n' ',' | sed 's/,$/\n/')d" ${list} reload=true else if [[ "${verbose}" == true ]]; then From 25601b9fcc4a87220cbd641deaf2f079b71994ee Mon Sep 17 00:00:00 2001 From: Dan Schaper Date: Sat, 13 May 2017 17:49:58 -0700 Subject: [PATCH 006/162] Document `sed` substitution for user readability Comment the oneliner with explanations of what each step does. --- advanced/Scripts/list.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh index 52c4c569..05806e46 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -158,6 +158,10 @@ RemoveDomain() { # Remove it from the other one echo "::: Removing $1 from $list..." # Busybox sed compatible case-insensitive domain removal + # grep case insensitive domain from list, print line numbers + # split on ':' with awk and print the line number + # For conditions with more than one match, substitute newline with ',' + # sed substitute final trailing ',' with newline sed -i "$(grep -in "^${domain}$" ${list} | awk -F':' '{print $1}' | tr '\n' ',' | sed 's/,$/\n/')d" ${list} reload=true else From b721ed49abaa7cacb743de5547199b3beb11cee4 Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Sun, 14 May 2017 11:11:44 +1000 Subject: [PATCH 007/162] Update Help Output (#1467) * File consistency * Tabs to 2 spaces * Corrected indenting * Double braced conditionals * Quoted variables within conditionals * Standardise core help text * Added help text for disable command * Added help text for logging command * Clean up * Fixed certain new lines and spaces * Sync with development branch * Formatting consistency * Tabs to 2 spaces * Corrected indenting * Double braced conditionals * Quoted variables within conditionals * Fixed certain newlines and spaces * Admin help text * Added help text for interface command * Sync with development branch * Formatting consistency * Tabs to 2 spaces * Fixed some wording * Fixed certain spaces * Formatting consistency * Minor wording changes * Tabs to 2 spaces * Corrected indenting * Double braced conditionals * Quoted variables within conditionals * Fixed certain newlines and spaces * Blacklist help text * Formatting consistency * Tabs to 2 spaces * Corrected indenting * Cronometer help text * Formatting consistency * Fixed certain newlines and spaces * Corrected indenting * Checkout warning alteration * Add checkout help text * Corrected help output --- advanced/Scripts/chronometer.sh | 131 ++++++------ advanced/Scripts/list.sh | 313 ++++++++++++++--------------- advanced/Scripts/piholeCheckout.sh | 30 +-- advanced/Scripts/version.sh | 168 +++++++++------- advanced/Scripts/webpage.sh | 187 ++++++++--------- pihole | 250 ++++++++++++----------- 6 files changed, 547 insertions(+), 532 deletions(-) diff --git a/advanced/Scripts/chronometer.sh b/advanced/Scripts/chronometer.sh index 67ff495b..b5d54e5f 100755 --- a/advanced/Scripts/chronometer.sh +++ b/advanced/Scripts/chronometer.sh @@ -8,101 +8,98 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. -#Functions############################################################################################################## +# Functions piLog="/var/log/pihole.log" gravity="/etc/pihole/gravity.list" . /etc/pihole/setupVars.conf function GetFTLData { - # Open connection to FTL - exec 3<>/dev/tcp/localhost/"$(cat /var/run/pihole-FTL.port)" + # Open connection to FTL + exec 3<>/dev/tcp/localhost/"$(cat /var/run/pihole-FTL.port)" - # Test if connection is open - if { >&3; } 2> /dev/null; then - # Send command to FTL - echo -e ">$1" >&3 + # Test if connection is open + if { >&3; } 2> /dev/null; then + # Send command to FTL + echo -e ">$1" >&3 - # Read input + # Read input + read -r -t 1 LINE <&3 + until [ ! $? ] || [[ "$LINE" == *"EOM"* ]]; do + echo "$LINE" >&1 read -r -t 1 LINE <&3 - until [ ! $? ] || [[ "$LINE" == *"EOM"* ]]; do - echo "$LINE" >&1 - read -r -t 1 LINE <&3 - done + done - # Close connection - exec 3>&- - exec 3<&- - fi + # Close connection + exec 3>&- + exec 3<&- + fi } outputJSON() { - get_summary_data - echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}" + get_summary_data + echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}" } get_summary_data() { - local summary=$(GetFTLData "stats") - domains_being_blocked_raw=$(grep "domains_being_blocked" <<< "${summary}" | grep -Eo "[0-9]+$") - domains_being_blocked=$(printf "%'.f" ${domains_being_blocked_raw}) - dns_queries_today_raw=$(grep "dns_queries_today" <<< "$summary" | grep -Eo "[0-9]+$") - dns_queries_today=$(printf "%'.f" ${dns_queries_today_raw}) - ads_blocked_today_raw=$(grep "ads_blocked_today" <<< "$summary" | grep -Eo "[0-9]+$") - ads_blocked_today=$(printf "%'.f" ${ads_blocked_today_raw}) - ads_percentage_today_raw=$(grep "ads_percentage_today" <<< "$summary" | grep -Eo "[0-9.]+$") - LC_NUMERIC=C ads_percentage_today=$(printf "%'.f" ${ads_percentage_today_raw}) + local summary=$(GetFTLData "stats") + domains_being_blocked_raw=$(grep "domains_being_blocked" <<< "${summary}" | grep -Eo "[0-9]+$") + domains_being_blocked=$(printf "%'.f" ${domains_being_blocked_raw}) + dns_queries_today_raw=$(grep "dns_queries_today" <<< "$summary" | grep -Eo "[0-9]+$") + dns_queries_today=$(printf "%'.f" ${dns_queries_today_raw}) + ads_blocked_today_raw=$(grep "ads_blocked_today" <<< "$summary" | grep -Eo "[0-9]+$") + ads_blocked_today=$(printf "%'.f" ${ads_blocked_today_raw}) + ads_percentage_today_raw=$(grep "ads_percentage_today" <<< "$summary" | grep -Eo "[0-9.]+$") + LC_NUMERIC=C ads_percentage_today=$(printf "%'.f" ${ads_percentage_today_raw}) } normalChrono() { - for (( ; ; )); do - get_summary_data - domain=$(GetFTLData recentBlocked) - clear - # Displays a colorful Pi-hole logo - echo " ___ _ _ _" - echo "| _ (_)___| |_ ___| |___" - echo "| _/ |___| ' \/ _ \ / -_)" - echo "|_| |_| |_||_\___/_\___|" - echo "" - echo " ${IPV4_ADDRESS}" - echo "" - uptime | cut -d' ' -f11- - #uptime -p #Doesn't work on all versions of uptime - uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}' - echo "-------------------------------" - echo "Recently blocked:" - echo " $domain" + for (( ; ; )); do + get_summary_data + domain=$(GetFTLData recentBlocked) + clear + # Displays a colorful Pi-hole logo + echo " ___ _ _ _" + echo "| _ (_)___| |_ ___| |___" + echo "| _/ |___| ' \/ _ \ / -_)" + echo "|_| |_| |_||_\___/_\___|" + echo "" + echo " ${IPV4_ADDRESS}" + echo "" + uptime | cut -d' ' -f11- + #uptime -p # Doesn't work on all versions of uptime + uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}' + echo "-------------------------------" + echo "Recently blocked:" + echo " $domain" - echo "Blocking: ${domains_being_blocked}" - echo "Queries: ${dns_queries_today}" - echo "Pi-holed: ${ads_blocked_today} (${ads_percentage_today}%)" + echo "Blocking: ${domains_being_blocked}" + echo "Queries: ${dns_queries_today}" + echo "Pi-holed: ${ads_blocked_today} (${ads_percentage_today}%)" - sleep 5 - done + sleep 5 + done } 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 0 + echo "Usage: pihole -c [options] +Example: 'pihole -c -j' +Calculates stats and displays to an LCD + +Options: + -j, --json Output stats as JSON formatted string + -h, --help Display this help text" + exit 0 } if [[ $# = 0 ]]; then - normalChrono + normalChrono fi for var in "$@"; do - case "$var" in - "-j" | "--json" ) outputJSON;; - "-h" | "--help" ) displayHelp;; - * ) exit 1;; - esac + 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 index 537ebac3..14b18249 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -3,14 +3,12 @@ # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. # -# Whitelists and blacklists domains +# Whitelist and blacklist domains # # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. - - -#globals +# Globals basename=pihole piholeDir=/etc/${basename} whitelist=${piholeDir}/whitelist.txt @@ -27,122 +25,120 @@ listMain="" listAlt="" helpFunc() { + if [[ "${listMain}" == "${whitelist}" ]]; then + letter="w" + word="white" + else + letter="b" + word="black" + fi - if [[ ${listMain} == ${whitelist} ]]; then - letter="w" - word="white" - else - letter="b" - word="black" - fi + echo "Usage: pihole -${letter} [options] +Example: 'pihole -${letter} site.com', or 'pihole -${letter} site1.com site2.com' +${word^}list one or more domains - 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 -if [[ "${letter}" == "b" ]]; then - echo "::: -wild, --wildcard Add wildcard entry (only blacklist)" -fi - exit 0 +Options:" + + if [[ "${letter}" == "b" ]]; then + echo " -wild, --wildcard Add wildcard entry to blacklist" + fi + +echo " -d, --delmode Remove domain(s) from the ${word}list + -nr, --noreload Update ${word}list without refreshing dnsmasq + -q, --quiet Make output less verbose + -h, --help Show this help dialog + -l, --list Display all your ${word}listed domains" + +exit 0 } EscapeRegexp() { - # This way we may safely insert an arbitrary - # string in our regular expressions - # Also remove leading "." if present - echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g" + # This way we may safely insert an arbitrary + # string in our regular expressions + # Also remove leading "." if present + echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g" } -HandleOther(){ - # First, convert everything to lowercase - domain=$(sed -e "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" <<< "$1") +HandleOther() { + # First, convert everything to lowercase + domain=$(sed -e "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" <<< "$1") - #check validity of domain - validDomain=$(echo "${domain}" | perl -lne 'print if /(?!.*[^a-z0-9-\.].*)^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9-]+\.)*[a-z]{2,63}/') - if [ -z "${validDomain}" ]; then - echo "::: $1 is not a valid argument or domain name" - else - domList=("${domList[@]}" ${validDomain}) - fi + # Check validity of domain + validDomain=$(echo "${domain}" | perl -lne 'print if /(?!.*[^a-z0-9-\.].*)^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9-]+\.)*[a-z]{2,63}/') + 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}" - if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then - RemoveDomain "${dom}" "${wildcardlist}" - fi - else - RemoveDomain "${dom}" "${listMain}" - fi - done + # Check whitelist file exists, and if not, create it + if [[ ! -f ${whitelist} ]]; then + touch ${whitelist} + fi + + for dom in "${domList[@]}"; do + # Logic: If addmode then add to desired list and remove from the other; if delmode then remove from desired list but do not add to the other + if ${addmode}; then + AddDomain "${dom}" "${listMain}" + RemoveDomain "${dom}" "${listAlt}" + if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then + RemoveDomain "${dom}" "${wildcardlist}" + fi + else + RemoveDomain "${dom}" "${listMain}" + fi + done } AddDomain() { - list="$2" - domain=$(EscapeRegexp "$1") + list="$2" + domain=$(EscapeRegexp "$1") - if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then + if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then + bool=true + # Is the domain in the list we want to add it to? + grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false - bool=true - #Is the domain in the list we want to add it to? - grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false + if [[ "${bool}" == false ]]; then + # Domain not found in the whitelist file, add it! + if [[ "${verbose}" == true ]]; then + echo "::: 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 + elif [[ "${list}" == "${wildcardlist}" ]]; then + source "${piholeDir}/setupVars.conf" + # Remove the /* from the end of the IPv4addr. + IPV4_ADDRESS=${IPV4_ADDRESS%/*} + IPV6_ADDRESS=${IPV6_ADDRESS} - 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 + bool=true + # Is the domain in the list? + grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false - elif [[ "${list}" == "${wildcardlist}" ]]; then - - source "${piholeDir}/setupVars.conf" - #Remove the /* from the end of the IPv4addr. - IPV4_ADDRESS=${IPV4_ADDRESS%/*} - IPV6_ADDRESS=${IPV6_ADDRESS} - - bool=true - #Is the domain in the list? - grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false - - if [[ "${bool}" == false ]]; then - if [[ "${verbose}" == true ]]; then - echo "::: Adding $1 to wildcard blacklist..." - fi - reload=true - echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}" - if [[ ${#IPV6_ADDRESS} > 0 ]] ; then - echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}" - fi - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} already exists in wildcard blacklist, no need to add!" - fi - fi - fi + if [[ "${bool}" == false ]]; then + if [[ "${verbose}" == true ]]; then + echo "::: Adding $1 to wildcard blacklist..." + fi + reload=true + echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}" + if [[ "${#IPV6_ADDRESS}" > 0 ]]; then + echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}" + fi + else + if [[ "${verbose}" == true ]]; then + echo "::: ${1} already exists in wildcard blacklist, no need to add!" + fi + fi + fi } RemoveDomain() { @@ -150,85 +146,82 @@ RemoveDomain() { domain=$(EscapeRegexp "$1") if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then - - bool=true - #Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa - grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false - if [[ "${bool}" == true ]]; then - # Remove it from the other one - echo "::: Removing $1 from $list..." - # /I flag: search case-insensitive - sed -i "/${domain}/Id" "${list}" - reload=true - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} does not exist in ${list}, no need to remove!" - fi + bool=true + # Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa + grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false + if [[ "${bool}" == true ]]; then + # Remove it from the other one + echo "::: Removing $1 from $list..." + # /I flag: search case-insensitive + sed -i "/${domain}/Id" "${list}" + reload=true + else + if [[ "${verbose}" == true ]]; then + echo "::: ${1} does not exist in ${list}, no need to remove!" fi - + fi elif [[ "${list}" == "${wildcardlist}" ]]; then - - bool=true - #Is it in the list? - grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false - if [[ "${bool}" == true ]]; then - # Remove it from the other one - echo "::: Removing $1 from $list..." - # /I flag: search case-insensitive - sed -i "/address=\/${domain}/Id" "${list}" - reload=true - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} does not exist in ${list}, no need to remove!" - fi + bool=true + # Is it in the list? + grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false + if [[ "${bool}" == true ]]; then + # Remove it from the other one + echo "::: Removing $1 from $list..." + # /I flag: search case-insensitive + sed -i "/address=\/${domain}/Id" "${list}" + reload=true + else + if [[ "${verbose}" == true ]]; then + echo "::: ${1} does not exist in ${list}, no need to remove!" fi + fi fi } Reload() { - # Reload hosts file - pihole -g -sd + # 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; + 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}";; - "-wild" | "wildcard" ) listMain="${wildcardlist}";; - "-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 + case "${var}" in + "-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";; + "-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";; + "-wild" | "wildcard" ) listMain="${wildcardlist}";; + "-nr"| "--noreload" ) reload=false;; + "-d" | "--delmode" ) addmode=false;; + "-f" | "--force" ) force=true;; + "-q" | "--quiet" ) verbose=false;; + "-h" | "--help" ) helpFunc;; + "-l" | "--list" ) Displaylist;; + * ) HandleOther "${var}";; + esac done shift if [[ $# = 0 ]]; then - helpFunc + helpFunc fi PoplistFile if ${reload}; then - Reload + Reload fi diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh index 09f20d6b..00bea12c 100644 --- a/advanced/Scripts/piholeCheckout.sh +++ b/advanced/Scripts/piholeCheckout.sh @@ -3,7 +3,7 @@ # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. # -# Checkout other branches than master +# Switch Pi-hole subsystems to a different Github branch # # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. @@ -18,9 +18,12 @@ PH_TEST="true" source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" # setupVars set in basic-install.sh source "${setupVars}" - update="false" +# Colour codes +red="\e[1;31m" +def="\e[0m" + fully_fetch_repo() { # Add upstream branches to shallow clone local directory="${1}" @@ -35,7 +38,7 @@ fully_fetch_repo() { return 0 } -get_available_branches(){ +get_available_branches() { # Return available branches local directory="${1}" @@ -79,23 +82,23 @@ checkout_pull_branch() { } warning1() { - echo "::: Note that changing the branch is a severe change of your Pi-hole system." - echo "::: This is not supported unless one of the developers explicitly asks you to do this!" - read -r -p "::: Have you read and understood this? [y/N] " response + echo " Please note that changing branches severely alters your Pi-hole subsystems" + echo " Features that work on the master branch, may not on a development branch" + echo -e " ${red}This feature is NOT supported unless a Pi-hole developer explicitly asks!${def}" + read -r -p " Have you read and understood this? [Y/N] " response case ${response} in [yY][eE][sS]|[yY]) - echo "::: Continuing." + echo "::: Continuing with branch change." return 0 ;; *) - echo "::: Aborting." + echo "::: Branch change has been cancelled." return 1 ;; esac } -checkout() -{ +checkout() { local corebranches local webbranches @@ -192,11 +195,10 @@ checkout() if [[ ! "${1}" == "web" && "${update}" == "true" ]]; then echo "::: Running installer to upgrade your installation" if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then - exit 0 + exit 0 else - echo "Unable to complete update, contact Pi-hole" - exit 1 + echo "Unable to complete update, contact Pi-hole" + exit 1 fi fi } - diff --git a/advanced/Scripts/version.sh b/advanced/Scripts/version.sh index 7f96e29a..73888295 100755 --- a/advanced/Scripts/version.sh +++ b/advanced/Scripts/version.sh @@ -3,24 +3,29 @@ # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. # -# shows version numbers +# Show version numbers # # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. # Variables DEFAULT="-1" -PHGITDIR="/etc/.pihole/" +COREGITDIR="/etc/.pihole/" WEBGITDIR="/var/www/html/admin/" getLocalVersion() { + # FTL requires a different method + if [[ "$1" == "FTL" ]]; then + pihole-FTL version + return 0 + fi + # Get the tagged version of the local repository local directory="${1}" local version - cd "${directory}" || { echo "${DEFAULT}"; return 1; } - version=$(git describe --tags --always || \ - echo "${DEFAULT}") + cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; } + version=$(git describe --tags --always || echo "$DEFAULT") if [[ "${version}" =~ ^v ]]; then echo "${version}" elif [[ "${version}" == "${DEFAULT}" ]]; then @@ -33,13 +38,18 @@ getLocalVersion() { } getLocalHash() { + # Local FTL hash does not exist on filesystem + if [[ "$1" == "FTL" ]]; then + echo "N/A" + return 0 + fi + # Get the short hash of the local repository local directory="${1}" local hash - cd "${directory}" || { echo "${DEFAULT}"; return 1; } - hash=$(git rev-parse --short HEAD || \ - echo "${DEFAULT}") + cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; } + hash=$(git rev-parse --short HEAD || echo "$DEFAULT") if [[ "${hash}" == "${DEFAULT}" ]]; then echo "ERROR" return 1 @@ -49,12 +59,33 @@ getLocalHash() { return 0 } +getRemoteHash(){ + # Remote FTL hash is not applicable + if [[ "$1" == "FTL" ]]; then + echo "N/A" + return 0 + fi + + local daemon="${1}" + local branch="${2}" + + hash=$(git ls-remote --heads "https://github.com/pi-hole/${daemon}" | \ + awk -v bra="$branch" '$0~bra {print substr($0,0,8);exit}') + if [[ -n "$hash" ]]; then + echo "$hash" + else + echo "ERROR" + return 1 + fi + return 0 +} + getRemoteVersion(){ # Get the version from the remote origin local daemon="${1}" local version - version=$(curl --silent --fail https://api.github.com/repos/pi-hole/${daemon}/releases/latest | \ + version=$(curl --silent --fail "https://api.github.com/repos/pi-hole/${daemon}/releases/latest" | \ awk -F: '$1 ~/tag_name/ { print $2 }' | \ tr -cd '[[:alnum:]]._-') if [[ "${version}" =~ ^v ]]; then @@ -66,72 +97,73 @@ getRemoteVersion(){ return 0 } -#PHHASHLATEST=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/commits/master | \ -# grep sha | \ -# head -n1 | \ -# awk -F ' ' '{ print $2 }' | \ -# tr -cd '[[:alnum:]]._-') - -#WEBHASHLATEST=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/commits/master | \ -# grep sha | \ -# head -n1 | \ -# awk -F ' ' '{ print $2 }' | \ -# tr -cd '[[:alnum:]]._-') - - -normalOutput() { - echo "::: Pi-hole version is $(getLocalVersion "${PHGITDIR}") (Latest version is $(getRemoteVersion pi-hole))" - if [ -d "${WEBGITDIR}" ]; then - echo "::: Web-Admin version is $(getLocalVersion "${WEBGITDIR}") (Latest version is $(getRemoteVersion AdminLTE))" - fi -} - -webOutput() { - if [ -d "${WEBGITDIR}" ]; then - case "${1}" in - "-l" | "--latest" ) echo $(getRemoteVersion AdminLTE);; - "-c" | "--current" ) echo $(getLocalVersion "${WEBGITDIR}");; - "-h" | "--hash" ) echo $(getLocalHash "${WEBGITDIR}");; - * ) echo "::: Invalid Option!"; exit 1; - esac - else - echo "::: Web interface not installed!"; exit 1; +versionOutput() { + [[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR + [[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR + [[ "$1" == "FTL" ]] && GITDIR="FTL" + + [[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $GITDIR) + [[ "$2" == "-l" ]] || [[ "$2" == "--latest" ]] || [[ -z "$2" ]] && latest=$(getRemoteVersion "$1") + if [[ "$2" == "-h" ]] || [[ "$2" == "--hash" ]]; then + [[ "$3" == "-c" ]] || [[ "$3" == "--current" ]] || [[ -z "$3" ]] && curHash=$(getLocalHash "$GITDIR") + [[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)") fi + + if [[ -n "$current" ]] && [[ -n "$latest" ]]; then + output="${1^} version is $current (Latest: $latest)" + elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then + output="Current ${1^} version is $current" + elif [[ -z "$current" ]] && [[ -n "$latest" ]]; then + output="Latest ${1^} version is $latest" + elif [[ "$curHash" == "N/A" ]] || [[ "$latHash" == "N/A" ]]; then + output="${1^} hash is not applicable" + elif [[ -n "$curHash" ]] && [[ -n "$latHash" ]]; then + output="${1^} hash is $curHash (Latest: $latHash)" + elif [[ -n "$curHash" ]] && [[ -z "$latHash" ]]; then + output="Current ${1^} hash is $curHash" + elif [[ -z "$curHash" ]] && [[ -n "$latHash" ]]; then + output="Latest ${1^} hash is $latHash" + else + errorOutput + fi + + [[ -n "$output" ]] && echo "$output" } -coreOutput() { - case "${1}" in - "-l" | "--latest" ) echo $(getRemoteVersion pi-hole);; - "-c" | "--current" ) echo $(getLocalVersion "${PHGITDIR}");; - "-h" | "--hash" ) echo $(getLocalHash "${PHGITDIR}");; - * ) echo "::: Invalid Option!"; exit 1; - esac +errorOutput() { + echo "Invalid Option! Try 'pihole -v -h' for more information." + exit 1 +} + +defaultOutput() { + versionOutput "pi-hole" "$@" + versionOutput "AdminLTE" "$@" + versionOutput "FTL" "$@" } 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 0 + echo "Usage: pihole -v [REPO | OPTION] [OPTION] +Example: 'pihole -v -p -l' +Show Pi-hole, Admin Console & FTL versions + +Repositories: + -p, --pihole Only retrieve info regarding Pi-hole repository + -a, --admin Only retrieve info regarding AdminLTE repository + -f, --ftl Only retrieve info regarding FTL repository + +Options: + -c, --current Return the current version + -l, --latest Return the latest version + -h, --hash Return the Github hash from your local repositories + --help Show this help dialog +" + exit 0 } -if [[ $# = 0 ]]; then - normalOutput -fi - case "${1}" in - "-a" | "--admin" ) shift; webOutput "$@";; - "-p" | "--pihole" ) shift; coreOutput "$@" ;; - "-h" | "--help" ) helpFunc;; + "-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";; + "-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";; + "-f" | "--ftl" ) shift; versionOutput "FTL" "$@";; + "--help" ) helpFunc;; + * ) defaultOutput "$@";; esac diff --git a/advanced/Scripts/webpage.sh b/advanced/Scripts/webpage.sh index d3ad3032..6626dab8 100755 --- a/advanced/Scripts/webpage.sh +++ b/advanced/Scripts/webpage.sh @@ -8,7 +8,6 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. - readonly setupVars="/etc/pihole/setupVars.conf" readonly dnsmasqconfig="/etc/dnsmasq.d/01-pihole.conf" readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf" @@ -16,23 +15,19 @@ readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf" readonly dhcpstaticconfig="/etc/dnsmasq.d/04-pihole-static-dhcp.conf" helpFunc() { - cat << EOM -::: Set admin options for the web interface of pihole -::: -::: Usage: pihole -a [options] -::: -::: Options: -::: -p, password Set web interface password, an empty input will remove any previously set password -::: -c, celsius Set Celsius temperature unit -::: -f, fahrenheit Set Fahrenheit temperature unit -::: -k, kelvin Set Kelvin temperature unit -::: -h, --help Show this help dialog -::: -i, interface Setup interface listening behavior of dnsmasq -::: pihole -a -i local : Listen on all interfaces, but allow only queries from -::: devices that are at most one hop away (local devices) -::: pihole -a -i single : Listen only on one interface (see PIHOLE_INTERFACE) -::: pihole -a -i all : Listen on all interfaces, permit all origins -EOM + echo "Usage: pihole -a [options] +Example: pihole -a -p password +Set options for the Admin Console + +Options: + -f, flush Flush the Pi-hole log + -p, password Set Admin Console password + -c, celsius Set Celsius as preferred temperature unit + -f, fahrenheit Set Fahrenheit as preferred temperature unit + -k, kelvin Set Kelvin as preferred temperature unit + -h, --help Show this help dialog + -i, interface Specify dnsmasq's interface listening behavior + Add '-h' for more info on interface usage" exit 0 } @@ -61,21 +56,18 @@ delete_dnsmasq_setting() { sed -i "/${1}/d" "${dnsmasqconfig}" } -SetTemperatureUnit(){ - +SetTemperatureUnit() { change_setting "TEMPERATUREUNIT" "${unit}" - } -HashPassword(){ - # Compute password hash twice to avoid rainbow table vulnerability - return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//') - return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//') - echo ${return} +HashPassword() { + # Compute password hash twice to avoid rainbow table vulnerability + return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//') + return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//') + echo ${return} } -SetWebPassword(){ - +SetWebPassword() { if [ "${SUDO_USER}" == "www-data" ]; then echo "Security measure: user www-data is not allowed to change webUI password!" echo "Exiting" @@ -175,8 +167,7 @@ trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE3 } -SetDNSServers(){ - +SetDNSServers() { # Save setting to file delete_setting "PIHOLE_DNS" IFS=',' read -r -a array <<< "${args[2]}" @@ -207,72 +198,59 @@ SetDNSServers(){ # Restart dnsmasq to load new configuration RestartDNS - } -SetExcludeDomains(){ - +SetExcludeDomains() { change_setting "API_EXCLUDE_DOMAINS" "${args[2]}" - } -SetExcludeClients(){ - +SetExcludeClients() { change_setting "API_EXCLUDE_CLIENTS" "${args[2]}" - } -Reboot(){ - +Reboot() { nohup bash -c "sleep 5; reboot" &> /dev/null /dev/null else service dnsmasq restart &> /dev/null fi - } -SetQueryLogOptions(){ - +SetQueryLogOptions() { change_setting "API_QUERY_LOG_SHOW" "${args[2]}" - } ProcessDHCPSettings() { - source "${setupVars}" if [[ "${DHCP_ACTIVE}" == "true" ]]; then + interface=$(grep 'PIHOLE_INTERFACE=' /etc/pihole/setupVars.conf | sed "s/.*=//") - interface=$(grep 'PIHOLE_INTERFACE=' /etc/pihole/setupVars.conf | sed "s/.*=//") + # Use eth0 as fallback interface + if [ -z ${interface} ]; then + interface="eth0" + fi - # Use eth0 as fallback interface - if [ -z ${interface} ]; then - interface="eth0" - fi + if [[ "${PIHOLE_DOMAIN}" == "" ]]; then + PIHOLE_DOMAIN="local" + change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}" + fi - if [[ "${PIHOLE_DOMAIN}" == "" ]]; then - PIHOLE_DOMAIN="local" - change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}" - fi + if [[ "${DHCP_LEASETIME}" == "0" ]]; then + leasetime="infinite" + elif [[ "${DHCP_LEASETIME}" == "" ]]; then + leasetime="24h" + change_setting "DHCP_LEASETIME" "${leasetime}" + else + leasetime="${DHCP_LEASETIME}h" + fi - if [[ "${DHCP_LEASETIME}" == "0" ]]; then - leasetime="infinite" - elif [[ "${DHCP_LEASETIME}" == "" ]]; then - leasetime="24h" - change_setting "DHCP_LEASETIME" "${leasetime}" - else - leasetime="${DHCP_LEASETIME}h" - fi - - # Write settings to file - echo "############################################################################### + # Write settings to file + echo "############################################################################### # DHCP SERVER CONFIG FILE AUTOMATICALLY POPULATED BY PI-HOLE WEB INTERFACE. # # ANY CHANGES MADE TO THIS FILE WILL BE LOST ON CHANGE # ############################################################################### @@ -283,26 +261,25 @@ dhcp-leasefile=/etc/pihole/dhcp.leases #quiet-dhcp " > "${dhcpconfig}" -if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then - echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}" -fi + if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then + echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}" + fi - if [[ "${DHCP_IPv6}" == "true" ]]; then -echo "#quiet-dhcp6 + if [[ "${DHCP_IPv6}" == "true" ]]; then + echo "#quiet-dhcp6 #enable-ra dhcp-option=option6:dns-server,[::] dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,${leasetime} ra-param=*,0,0 " >> "${dhcpconfig}" - fi + fi else rm "${dhcpconfig}" &> /dev/null fi } -EnableDHCP(){ - +EnableDHCP() { change_setting "DHCP_ACTIVE" "true" change_setting "DHCP_START" "${args[2]}" change_setting "DHCP_END" "${args[3]}" @@ -320,8 +297,7 @@ EnableDHCP(){ RestartDNS } -DisableDHCP(){ - +DisableDHCP() { change_setting "DHCP_ACTIVE" "false" # Remove possible old setting from file @@ -333,23 +309,20 @@ DisableDHCP(){ RestartDNS } -SetWebUILayout(){ - +SetWebUILayout() { change_setting "WEBUIBOXEDLAYOUT" "${args[2]}" - } CustomizeAdLists() { - list="/etc/pihole/adlists.list" - if [[ "${args[2]}" == "enable" ]] ; then + if [[ "${args[2]}" == "enable" ]]; then sed -i "\\@${args[3]}@s/^#http/http/g" "${list}" - elif [[ "${args[2]}" == "disable" ]] ; then + elif [[ "${args[2]}" == "disable" ]]; then sed -i "\\@${args[3]}@s/^http/#http/g" "${list}" - elif [[ "${args[2]}" == "add" ]] ; then + elif [[ "${args[2]}" == "add" ]]; then echo "${args[3]}" >> ${list} - elif [[ "${args[2]}" == "del" ]] ; then + elif [[ "${args[2]}" == "del" ]]; then var=$(echo "${args[3]}" | sed 's/\//\\\//g') sed -i "/${var}/Id" "${list}" else @@ -358,18 +331,15 @@ CustomizeAdLists() { fi } -SetPrivacyMode(){ - - if [[ "${args[2]}" == "true" ]] ; then +SetPrivacyMode() { + if [[ "${args[2]}" == "true" ]]; then change_setting "API_PRIVACY_MODE" "true" else change_setting "API_PRIVACY_MODE" "false" fi - } ResolutionSettings() { - typ="${args[2]}" state="${args[3]}" @@ -378,11 +348,9 @@ ResolutionSettings() { elif [[ "${typ}" == "clients" ]]; then change_setting "API_GET_CLIENT_HOSTNAME" "${state}" fi - } AddDHCPStaticAddress() { - mac="${args[2]}" ip="${args[3]}" host="${args[4]}" @@ -397,18 +365,14 @@ AddDHCPStaticAddress() { # Full info given echo "dhcp-host=${mac},${ip},${host}" >> "${dhcpstaticconfig}" fi - } RemoveDHCPStaticAddress() { - mac="${args[2]}" sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}" - } -SetHostRecord(){ - +SetHostRecord() { if [ -n "${args[3]}" ]; then change_setting "HOSTRECORD" "${args[2]},${args[3]}" echo "Setting host record for ${args[2]} -> ${args[3]}" @@ -421,17 +385,28 @@ SetHostRecord(){ # Restart dnsmasq to load new configuration RestartDNS - } -SetListeningMode(){ - +SetListeningMode() { source "${setupVars}" + + if [[ "$3" == "-h" ]]; then + echo "Usage: pihole -a -i [interface] +Example: 'pihole -a -i local' +Specify dnsmasq's network interface listening behavior - if [[ "${args[2]}" == "all" ]] ; then +Interfaces: + local Listen on all interfaces, but only allow queries from + devices that are at most one hop away (local devices) + single Listen only on ${PIHOLE_INTERFACE} interface + all Listen on all interfaces, permit all origins" + exit 0 + fi + + if [[ "${args[2]}" == "all" ]]; then echo "Listening on all interfaces, permiting all origins, hope you have a firewall!" change_setting "DNSMASQ_LISTENING" "all" - elif [[ "${args[2]}" == "local" ]] ; then + elif [[ "${args[2]}" == "local" ]]; then echo "Listening on all interfaces, permitting only origins that are at most one hop away (local devices)" change_setting "DNSMASQ_LISTENING" "local" else @@ -446,17 +421,14 @@ SetListeningMode(){ # Restart dnsmasq to load new configuration RestartDNS fi - } -Teleporter() -{ +Teleporter() { local datetimestamp=$(date "+%Y-%m-%d_%H-%M-%S") php /var/www/html/admin/scripts/pi-hole/php/teleporter.php > "pi-hole-teleporter_${datetimestamp}.zip" } main() { - args=("$@") case "${args[1]}" in @@ -479,7 +451,7 @@ main() { "addstaticdhcp" ) AddDHCPStaticAddress;; "removestaticdhcp" ) RemoveDHCPStaticAddress;; "hostrecord" ) SetHostRecord;; - "-i" | "interface" ) SetListeningMode;; + "-i" | "interface" ) SetListeningMode "$@";; "-t" | "teleporter" ) Teleporter;; "adlist" ) CustomizeAdLists;; * ) helpFunc;; @@ -490,5 +462,4 @@ main() { if [[ $# = 0 ]]; then helpFunc fi - } diff --git a/pihole b/pihole index 83e13000..79a5c35d 100755 --- a/pihole +++ b/pihole @@ -9,11 +9,11 @@ # Please see LICENSE file for your rights under this license. readonly PI_HOLE_SCRIPT_DIR="/opt/pihole" - readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf" + # Must be root to use this tool if [[ ! $EUID -eq 0 ]];then - if [ -x "$(command -v sudo)" ];then + if [[ -x "$(command -v sudo)" ]]; then exec sudo bash "$0" "$@" exit $? else @@ -80,66 +80,49 @@ updateGravityFunc() { exit 0 } -scanList(){ +scanList() { domain="${1}" list="${2}" method="${3}" - if [[ ${method} == "-exact" ]] ; then - grep -i -E "(^|\s)${domain}($|\s)" "${list}" - else - grep -i "${domain}" "${list}" - fi -} -processWildcards() { - IFS="." read -r -a array <<< "${1}" - for (( i=${#array[@]}-1; i>=0; i-- )); do - ar="" - for (( j=${#array[@]}-1; j>${#array[@]}-i-2; j-- )); do - if [[ $j == $((${#array[@]}-1)) ]]; then - ar="${array[$j]}" - else - ar="${array[$j]}.${ar}" - fi - done - echo "${ar}" - done + if [[ "${method}" == "-exact" ]]; then + grep -i -E -l "(^|\s|\/)${domain}($|\s|\/)" ${list} + else + grep -i "${domain}" ${list} + fi } queryFunc() { - domain="${2}" method="${3}" - lists=( /etc/pihole/list.* /etc/pihole/blacklist.txt) - for list in ${lists[@]}; do - if [ -e "${list}" ]; then - result=$(scanList ${domain} ${list} ${method}) - # Remove empty lines before couting number of results - count=$(sed '/^\s*$/d' <<< "$result" | wc -l) - echo "::: ${list} (${count} results)" - if [[ ${count} > 0 ]]; then - echo "${result}" - fi - echo "" - else - echo "::: ${list} does not exist" - echo "" - fi - done - - # Scan for possible wildcard matches - if [ -e "${wildcardlist}" ]; then - local wildcards=($(processWildcards "${domain}")) - for domain in ${wildcards[@]}; do - result=$(scanList "\/${domain}\/" ${wildcardlist}) - # Remove empty lines before couting number of results - count=$(sed '/^\s*$/d' <<< "$result" | wc -l) - if [[ ${count} > 0 ]]; then - echo "::: Wildcard blocking ${domain} (${count} results)" - echo "${result}" - echo "" - fi - done + + # If domain contains non ASCII characters, convert domain to punycode if python exists + # Cr: https://serverfault.com/a/335079 + if [[ -z "${2}" ]]; then + echo "::: No domain specified" + exit 1 + elif [[ "${2}" = *[![:ascii:]]* ]]; then + [[ "$(which python)" ]] && domain=$(python -c 'import sys;print sys.argv[1].decode("utf-8").encode("idna")' "${2}") + else + domain="${2}" fi + + # Scan Whitelist, Blacklist and Wildcards + lists="/etc/pihole/whitelist.txt /etc/pihole/blacklist.txt $wildcardlist" + result=$(scanList ${domain} "${lists}" ${method}) + if [[ -n "$result" ]]; then + echo "$result" + [[ ! -t 1 ]] && exit 0 + fi + + # Scan Domains lists + result=$(scanList ${domain} "/etc/pihole/*.domains" ${method}) + if [[ -n "$result" ]]; then + sort -t . -k 2 -g <<< "$result" + else + [ -n "$method" ] && exact="exact " + echo "::: No ${exact}results found for ${domain}" + fi + exit 0 } @@ -163,16 +146,16 @@ versionFunc() { restartDNS() { dnsmasqPid=$(pidof dnsmasq) - if [[ ${dnsmasqPid} ]]; then - # service already running - reload config - if [ -x "$(command -v systemctl)" ]; then + if [[ "${dnsmasqPid}" ]]; then + # Service already running - reload config + if [[ -x "$(command -v systemctl)" ]]; then systemctl restart dnsmasq else service dnsmasq restart fi else - # service not running, start it up - if [ -x "$(command -v systemctl)" ]; then + # Service not running, start it up + if [[ -x "$(command -v systemctl)" ]]; then systemctl start dnsmasq else service dnsmasq start @@ -181,16 +164,25 @@ restartDNS() { } piholeEnable() { - if [[ "${1}" == "0" ]] ; then - #Disable Pihole + if [[ "${2}" == "-h" ]]; then + echo "Usage: pihole disable [time] +Example: 'pihole disable', or 'pihole disable 5m' +Disable Pi-hole subsystems + +Time: + #s Disable Pi-hole functionality for # second(s) + #m Disable Pi-hole functionality for # minute(s)" + exit 0 + elif [[ "${1}" == "0" ]]; then + # Disable Pi-hole sed -i 's/^addn-hosts=\/etc\/pihole\/gravity.list/#addn-hosts=\/etc\/pihole\/gravity.list/' /etc/dnsmasq.d/01-pihole.conf echo "::: Blocking has been disabled!" - if [[ $# > 1 ]] ; then - if [[ ${2} == *"s"* ]] ; then + if [[ $# > 1 ]]; then + if [[ "${2}" == *"s"* ]]; then tt=${2%"s"} echo "::: Blocking will be re-enabled in ${tt} seconds" nohup bash -c "sleep ${tt}; pihole enable" /dev/null & - elif [[ ${2} == *"m"* ]] ; then + elif [[ "${2}" == *"m"* ]]; then tt=${2%"m"} echo "::: Blocking will be re-enabled in ${tt} minutes" tt=$((${tt}*60)) @@ -204,7 +196,7 @@ piholeEnable() { fi fi else - #Enable pihole + # Enable Pi-hole echo "::: Blocking has been enabled!" sed -i 's/^#addn-hosts/addn-hosts/' /etc/dnsmasq.d/01-pihole.conf fi @@ -213,15 +205,23 @@ piholeEnable() { piholeLogging() { shift + if [[ "${1}" == "-h" ]]; then + echo "Usage: pihole logging [options] +Example: 'pihole logging on' +Specify whether the Pi-hole log should be used - if [[ "${1}" == "off" ]] ; then - #Disable Logging +Options: + on Enable the Pi-hole log at /var/log/pihole.log + off Disable the Pi-hole log at /var/log/pihole.log" + exit 0 + elif [[ "${1}" == "off" ]]; then + # Disable logging sed -i 's/^log-queries/#log-queries/' /etc/dnsmasq.d/01-pihole.conf sed -i 's/^QUERY_LOGGING=true/QUERY_LOGGING=false/' /etc/pihole/setupVars.conf pihole -f echo "::: Logging has been disabled!" - elif [[ "${1}" == "on" ]] ; then - #Enable logging + elif [[ "${1}" == "on" ]]; then + # Enable logging sed -i 's/^#log-queries/log-queries/' /etc/dnsmasq.d/01-pihole.conf sed -i 's/^QUERY_LOGGING=false/QUERY_LOGGING=true/' /etc/pihole/setupVars.conf echo "::: Logging has been enabled!" @@ -233,12 +233,12 @@ piholeLogging() { } piholeStatus() { - if [[ $(netstat -plnt | grep -c ':53 ') > 0 ]]; then - if [[ "${1}" != "web" ]] ; then + if [[ "$(netstat -plnt | grep -c ':53 ')" -gt "0" ]]; then + if [[ "${1}" != "web" ]]; then echo "::: DNS service is running" fi else - if [[ "${1}" == "web" ]] ; then + if [[ "${1}" == "web" ]]; then echo "-1"; else echo "::: DNS service is NOT running" @@ -246,28 +246,28 @@ piholeStatus() { return fi - if [[ $(grep -i "^#addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf) ]] ; then - #list is commented out - if [[ "${1}" == "web" ]] ; then + if [[ "$(grep -i "^#addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf)" ]]; then + # List is commented out + if [[ "${1}" == "web" ]]; then echo 0; else echo "::: Pi-hole blocking is Disabled"; fi - elif [[ $(grep -i "^addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf) ]] ; then - #list set - if [[ "${1}" == "web" ]] ; then + elif [[ "$(grep -i "^addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf)" ]]; 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 + # 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 + # Add addn-host= to dnsmasq echo "addn-hosts=/etc/pihole/gravity.list" >> /etc/dnsmasq.d/01-pihole.conf restartDNS fi @@ -280,46 +280,66 @@ tailFunc() { } piholeCheckoutFunc() { + if [[ "$2" == "-h" ]]; then + echo "Usage: pihole checkout [repo] [branch] +Example: 'pihole checkout master' or 'pihole checkout core dev' +Switch Pi-hole subsystems to a different Github branch + +Repositories: + core [branch] Change the branch of Pi-hole's core subsystem + web [branch] Change the branch of Admin Console subsystem + +Branches: + master Update subsystems to the latest stable release + dev Update subsystems to the latest development release" + exit 0 + fi + source "${PI_HOLE_SCRIPT_DIR}"/piholeCheckout.sh shift checkout "$@" } helpFunc() { - cat << EOM -::: Control all Pi-hole specific functions -::: -::: Usage: pihole [options] -::: Add -h after -w (whitelist), -b (blacklist), -c (chronometer), or -a (admin) for more information on usage -::: -::: Options: -::: -w, whitelist Whitelist domain(s) -::: -b, blacklist Blacklist domain(s) (exact match) -::: -wild, wildcard Blacklist whole domain(s) (wildcard) -::: -d, debug Start a debugging session -::: Automated debugging can be enabled with '-a'. -::: 'pihole -d -a' -::: -f, flush Flush the 'pihole.log' file -::: -t, tail Output the last lines of the 'pihole.log' file. Lines are appended as the file grows -::: -up, updatePihole Update Pi-hole components -::: -r, reconfigure Reconfigure or Repair Pi-hole -::: -g, updateGravity Update the list of ad-serving domains -::: -c, chronometer Calculates stats and displays to an LCD -::: -h, help Show this help dialog -::: -v, version Show installed versions of Pi-hole and Web-Admin -::: -q, query Query the adlists for a specific domain -::: 'pihole -q domain -exact' shows exact matches only -::: -l, logging Enable or Disable logging (pass 'on' or 'off') -::: -a, admin Admin webpage options -::: uninstall Uninstall Pi-hole from your system! :( -::: status Display if Pi-hole is Enabled or Disabled -::: enable Enable Pi-hole DNS Blocking -::: disable Disable Pi-hole DNS Blocking -::: Blocking can also be disabled only temporarily, e.g., -::: 'pihole disable 5m' - will disable blocking for 5 minutes -::: restartdns Restart dnsmasq -::: checkout Check out different branches -EOM + echo "Usage: pihole [options] +Example: 'pihole -w -h' +Add '-h' after specific commands for more information on usage + +Whitelist/Blacklist Options: + -w, whitelist Whitelist domain(s) + -b, blacklist Blacklist domain(s) + -wild, wildcard Blacklist domain(s), and all its subdomains + Add '-h' for more info on whitelist/blacklist usage + +Debugging Options: + -d, debug Start a debugging session + Add '-a' to enable automated debugging + -f, flush Flush the Pi-hole log + -r, reconfigure Reconfigure or Repair Pi-hole subsystems + -t, tail View the live output of the Pi-hole log + +Options: + -a, admin Admin Console options + Add '-h' for more info on admin console usage + -c, chronometer Calculates stats and displays to an LCD + Add '-h' for more info on chronometer usage + -g, updateGravity Update the list of ad-serving domains + -h, --help, help Show this help dialog + -l, logging Specify whether the Pi-hole log should be used + Add '-h' for more info on logging usage + -q, query Query the adlists for a specified domain + Add '-exact' AFTER a specified domain for exact match + -up, updatePihole Update Pi-hole subsystems + -v, version Show installed versions of Pi-hole, Admin Console & FTL + Add '-h' for more info on version usage + uninstall Uninstall Pi-hole from your system + status Display the running status of Pi-hole subsystems + enable Enable Pi-hole subsystems + disable Disable Pi-hole subsystems + Add '-h' for more info on disable usage + restartdns Restart Pi-hole subsystems + checkout Switch Pi-hole subsystems to a different Github branch + Add '-h' for more info on checkout usage"; exit 0 } @@ -344,7 +364,7 @@ case "${1}" in "-l" | "logging" ) piholeLogging "$@";; "uninstall" ) uninstallFunc;; "enable" ) piholeEnable 1;; - "disable" ) piholeEnable 0 $2;; + "disable" ) piholeEnable 0 "$2";; "status" ) piholeStatus "$2";; "restartdns" ) restartDNS;; "-a" | "admin" ) webpageFunc "$@";; From 0e4473685bb9fdc00f196cf2751be99c6877368c Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Sun, 14 May 2017 11:47:56 +1000 Subject: [PATCH 008/162] Show help for "pihole -a -i --help" --- advanced/Scripts/webpage.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced/Scripts/webpage.sh b/advanced/Scripts/webpage.sh index 6626dab8..8419aa8d 100755 --- a/advanced/Scripts/webpage.sh +++ b/advanced/Scripts/webpage.sh @@ -390,7 +390,7 @@ SetHostRecord() { SetListeningMode() { source "${setupVars}" - if [[ "$3" == "-h" ]]; then + if [[ "$3" == "-h" ]] || [[ "$3" == "--help" ]]; then echo "Usage: pihole -a -i [interface] Example: 'pihole -a -i local' Specify dnsmasq's network interface listening behavior From 4eb7d2868ca2d347ed0a497b6fb5c3a195ac4bf6 Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Sun, 14 May 2017 11:53:40 +1000 Subject: [PATCH 009/162] Fix "pihole disable --help" and "pihole -l --help" --- pihole | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pihole b/pihole index 79a5c35d..1b75add5 100755 --- a/pihole +++ b/pihole @@ -164,7 +164,7 @@ restartDNS() { } piholeEnable() { - if [[ "${2}" == "-h" ]]; then + if [[ "${2}" == "-h" ]] || [[ "${2}" == "--help" ]]; then echo "Usage: pihole disable [time] Example: 'pihole disable', or 'pihole disable 5m' Disable Pi-hole subsystems @@ -205,7 +205,7 @@ Time: piholeLogging() { shift - if [[ "${1}" == "-h" ]]; then + if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then echo "Usage: pihole logging [options] Example: 'pihole logging on' Specify whether the Pi-hole log should be used From 3bd677c102fddcce8ce72c81ae811b7453b8caa8 Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Sun, 14 May 2017 11:57:46 +1000 Subject: [PATCH 010/162] Show help for "pihole -v -h" * Indent output text * Minor help text change --- advanced/Scripts/version.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/advanced/Scripts/version.sh b/advanced/Scripts/version.sh index 73888295..50bdb608 100755 --- a/advanced/Scripts/version.sh +++ b/advanced/Scripts/version.sh @@ -104,7 +104,7 @@ versionOutput() { [[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $GITDIR) [[ "$2" == "-l" ]] || [[ "$2" == "--latest" ]] || [[ -z "$2" ]] && latest=$(getRemoteVersion "$1") - if [[ "$2" == "-h" ]] || [[ "$2" == "--hash" ]]; then + if [[ "$2" == "--hash" ]]; then [[ "$3" == "-c" ]] || [[ "$3" == "--current" ]] || [[ -z "$3" ]] && curHash=$(getLocalHash "$GITDIR") [[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)") fi @@ -127,11 +127,11 @@ versionOutput() { errorOutput fi - [[ -n "$output" ]] && echo "$output" + [[ -n "$output" ]] && echo " $output" } errorOutput() { - echo "Invalid Option! Try 'pihole -v -h' for more information." + echo " Invalid Option! Try 'pihole -v -h' for more information." exit 1 } @@ -142,7 +142,7 @@ defaultOutput() { } helpFunc() { - echo "Usage: pihole -v [REPO | OPTION] [OPTION] + echo "Usage: pihole -v [repo | option] [option] Example: 'pihole -v -p -l' Show Pi-hole, Admin Console & FTL versions @@ -154,8 +154,8 @@ Repositories: Options: -c, --current Return the current version -l, --latest Return the latest version - -h, --hash Return the Github hash from your local repositories - --help Show this help dialog + --hash Return the Github hash from your local repositories + -h, --help Show this help dialog " exit 0 } @@ -164,6 +164,6 @@ case "${1}" in "-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";; "-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";; "-f" | "--ftl" ) shift; versionOutput "FTL" "$@";; - "--help" ) helpFunc;; + "-h" | "--help" ) helpFunc;; * ) defaultOutput "$@";; esac From 39b74ebfd47e1847ebaff7cfabccb6fdc7d20f90 Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Sun, 14 May 2017 12:22:19 +1000 Subject: [PATCH 011/162] Show help for "pihole checkout --help" --- pihole | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pihole b/pihole index 1b75add5..c1359ef9 100755 --- a/pihole +++ b/pihole @@ -280,7 +280,7 @@ tailFunc() { } piholeCheckoutFunc() { - if [[ "$2" == "-h" ]]; then + if [[ "$2" == "-h" ]] || [[ "$2" == "--help" ]]; then echo "Usage: pihole checkout [repo] [branch] Example: 'pihole checkout master' or 'pihole checkout core dev' Switch Pi-hole subsystems to a different Github branch From da9ff0cc66929401f82cd6db2536288a187f8021 Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Sun, 14 May 2017 19:27:14 +1000 Subject: [PATCH 012/162] Tricorder: Insecure Opt-out * Check to see if Tricorder is being called directly * Provide opt-out for insecure transmission of debug log * Remove mention of internal function from help menu --- pihole | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/pihole b/pihole index f24461d3..8cffb5b2 100755 --- a/pihole +++ b/pihole @@ -269,10 +269,24 @@ piholeCheckoutFunc() { } tricorderFunc() { + if [ ! -p "/dev/stdin" ]; then + echo "Please do not call Tricorder directly." + exit 1 + fi + if command -v openssl &> /dev/null; then openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin else - nc tricorder.pi-hole.net 9999 < /dev/stdin + echo "The debug log will be transmitted insecurely via plain-text" + echo "If you wish to cancel, press Ctrl-C to exit within 10 seconds" + secs="10" + while [ "$secs" -gt 0 ]; do + echo -ne "." + sleep 1 + : $((secs--)) + done + echo " " + nc tricorder.pi-hole.net 9999 < /dev/stdin < /dev/stdin fi } @@ -310,7 +324,6 @@ helpFunc() { ::: 'pihole disable 5m' - will disable blocking for 5 minutes ::: restartdns Restart dnsmasq ::: checkout Check out different branches -::: tricorder Upload log to Pi-hole's medical tricorder (uses SSL when possible) EOM exit 0 } From 69f361a3a1884879fe18ec8c1dccc09fabfc3815 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 14 May 2017 16:28:35 +0200 Subject: [PATCH 013/162] :taco: is the new :shipit: squirrel --- .pullapprove.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pullapprove.yml b/.pullapprove.yml index 39566b34..188a64f2 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -10,7 +10,7 @@ group_defaults: reset_on_push: enabled: true reject_value: -2 - approve_regex: '^(Approved|:shipit:|:\+1:|Engage)' + approve_regex: '^(Approved|:shipit:|:\+1:|Engage|:taco:)' reject_regex: '^(Rejected|:-1:|Borg)' author_approval: auto: true From b9f2ba07173663d011f0bd4a2c2e7dea548ffac3 Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Tue, 16 May 2017 09:48:46 +1000 Subject: [PATCH 014/162] Wording changes and bug fix --- pihole | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pihole b/pihole index 8cffb5b2..a630d67d 100755 --- a/pihole +++ b/pihole @@ -277,7 +277,8 @@ tricorderFunc() { if command -v openssl &> /dev/null; then openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin else - echo "The debug log will be transmitted insecurely via plain-text" + echo "Your debug log will be transmitted unencrypted via plain-text" + echo "There is a possibility that this could be intercepted by a third party" echo "If you wish to cancel, press Ctrl-C to exit within 10 seconds" secs="10" while [ "$secs" -gt 0 ]; do @@ -286,7 +287,7 @@ tricorderFunc() { : $((secs--)) done echo " " - nc tricorder.pi-hole.net 9999 < /dev/stdin < /dev/stdin + nc tricorder.pi-hole.net 9999 < /dev/stdin fi } From 7453bf2ee62dfb9c79384ef43856a7446e4173da Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Tue, 16 May 2017 10:23:53 +1000 Subject: [PATCH 015/162] Fix wildcard help text * -wild is not a valid option since we're already using -wild --- advanced/Scripts/list.sh | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh index 378d8402..308e1f5e 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -40,13 +40,8 @@ helpFunc() { Example: 'pihole -${param} site.com', or 'pihole -${param} site1.com site2.com' ${type^}list one or more domains -Options:" - - if [[ "${listMain}" == "${wildcardlist}" ]]; then - echo " -wild, --wildcard Block all subdomains of specified domain" - fi - -echo " -d, --delmode Remove domain(s) from the ${type}list +Options: + -d, --delmode Remove domain(s) from the ${type}list -nr, --noreload Update ${type}list without refreshing dnsmasq -q, --quiet Make output less verbose -h, --help Show this help dialog From 4e2c6a7b8e6e5825f6e609daf0694b483e27f55c Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 17 May 2017 12:44:35 +0200 Subject: [PATCH 016/162] Fix logrotation: manual flushing should be done twice, but automated rotation at midnight should only be done *once*! --- advanced/Scripts/piholeLogFlush.sh | 34 ++++++++++++++++++++++-------- advanced/pihole.cron | 2 +- pihole | 4 ++-- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/advanced/Scripts/piholeLogFlush.sh b/advanced/Scripts/piholeLogFlush.sh index 8e4c8266..0a4d12bc 100755 --- a/advanced/Scripts/piholeLogFlush.sh +++ b/advanced/Scripts/piholeLogFlush.sh @@ -9,16 +9,32 @@ # Please see LICENSE file for your rights under this license. echo -n "::: Flushing /var/log/pihole.log ..." -# Test if logrotate is available on this system -if command -v /usr/sbin/logrotate >/dev/null; then - # Flush twice to move all data out of sight of FTL - /usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3 - /usr/sbin/logrotate --force /etc/pihole/logrotate +if [[ "$@" == *"once"* ]]; then + # Nightly logrotation + if command -v /usr/sbin/logrotate >/dev/null; then + # Logrotate once + /usr/sbin/logrotate --force /etc/pihole/logrotate + else + # Copy pihole.log over to pihole.log.1 + # and empty out pihole.log + # Note that moving the file is not an option, as + # dnsmasq would happily continue writing into the + # moved file (it will have the same file handler) + cp /var/log/pihole.log /var/log/pihole.log.1 + echo " " > /var/log/pihole.log + fi else - # Flush both pihole.log and pihole.log.1 (if existing) - echo " " > /var/log/pihole.log - if [ -f /var/log/pihole.log.1 ]; then - echo " " > /var/log/pihole.log.1 + # Manual flushing + if command -v /usr/sbin/logrotate >/dev/null; then + # Logrotate twice to move all data out of sight of FTL + /usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3 + /usr/sbin/logrotate --force /etc/pihole/logrotate + else + # Flush both pihole.log and pihole.log.1 (if existing) + echo " " > /var/log/pihole.log + if [ -f /var/log/pihole.log.1 ]; then + echo " " > /var/log/pihole.log.1 + fi fi fi echo "... done!" diff --git a/advanced/pihole.cron b/advanced/pihole.cron index c885b371..be35dc50 100644 --- a/advanced/pihole.cron +++ b/advanced/pihole.cron @@ -24,6 +24,6 @@ # 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 # The flush script will use logrotate if available -00 00 * * * root PATH="$PATH:/usr/local/bin/" pihole flush +00 00 * * * root PATH="$PATH:/usr/local/bin/" pihole flush once @reboot root /usr/sbin/logrotate /etc/pihole/logrotate diff --git a/pihole b/pihole index feebbc1c..d116e248 100755 --- a/pihole +++ b/pihole @@ -61,7 +61,7 @@ debugFunc() { } flushFunc() { - "${PI_HOLE_SCRIPT_DIR}"/piholeLogFlush.sh + "${PI_HOLE_SCRIPT_DIR}"/piholeLogFlush.sh "$@" exit 0 } @@ -353,7 +353,7 @@ case "${1}" in "-b" | "blacklist" ) blacklistFunc "$@";; "-wild" | "wildcard" ) wildcardFunc "$@";; "-d" | "debug" ) debugFunc "$@";; - "-f" | "flush" ) flushFunc;; + "-f" | "flush" ) flushFunc "$@";; "-up" | "updatePihole" ) updatePiholeFunc;; "-r" | "reconfigure" ) reconfigurePiholeFunc;; "-g" | "updateGravity" ) updateGravityFunc "$@";; From c9042ffedd110485bd4e248fb2737a6c283fcc01 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 17 May 2017 12:51:04 +0200 Subject: [PATCH 017/162] Print echos only when manual flushing is requested --- advanced/Scripts/piholeLogFlush.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/advanced/Scripts/piholeLogFlush.sh b/advanced/Scripts/piholeLogFlush.sh index 0a4d12bc..9801d8ac 100755 --- a/advanced/Scripts/piholeLogFlush.sh +++ b/advanced/Scripts/piholeLogFlush.sh @@ -8,7 +8,6 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. -echo -n "::: Flushing /var/log/pihole.log ..." if [[ "$@" == *"once"* ]]; then # Nightly logrotation if command -v /usr/sbin/logrotate >/dev/null; then @@ -25,6 +24,7 @@ if [[ "$@" == *"once"* ]]; then fi else # Manual flushing + echo -n "::: Flushing /var/log/pihole.log ..." if command -v /usr/sbin/logrotate >/dev/null; then # Logrotate twice to move all data out of sight of FTL /usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3 @@ -36,5 +36,5 @@ else echo " " > /var/log/pihole.log.1 fi fi + echo "... done!" fi -echo "... done!" From 42eb811910ddb2fcd4a39a1a49b922686126ebce Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 17 May 2017 12:54:43 +0200 Subject: [PATCH 018/162] Add "quiet" mode + update comments in the cron file --- advanced/Scripts/piholeLogFlush.sh | 7 ++++++- advanced/pihole.cron | 7 ++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/advanced/Scripts/piholeLogFlush.sh b/advanced/Scripts/piholeLogFlush.sh index 9801d8ac..cc553b32 100755 --- a/advanced/Scripts/piholeLogFlush.sh +++ b/advanced/Scripts/piholeLogFlush.sh @@ -8,6 +8,9 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. +if [[ "$@" != *"quiet"* ]]; then + echo -n "::: Flushing /var/log/pihole.log ..." +fi if [[ "$@" == *"once"* ]]; then # Nightly logrotation if command -v /usr/sbin/logrotate >/dev/null; then @@ -24,7 +27,6 @@ if [[ "$@" == *"once"* ]]; then fi else # Manual flushing - echo -n "::: Flushing /var/log/pihole.log ..." if command -v /usr/sbin/logrotate >/dev/null; then # Logrotate twice to move all data out of sight of FTL /usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3 @@ -36,5 +38,8 @@ else echo " " > /var/log/pihole.log.1 fi fi +fi + +if [[ "$@" != *"quiet"* ]]; then echo "... done!" fi diff --git a/advanced/pihole.cron b/advanced/pihole.cron index be35dc50..f1beb08c 100644 --- a/advanced/pihole.cron +++ b/advanced/pihole.cron @@ -21,9 +21,10 @@ # Pi-hole: Update Pi-hole! Uncomment to enable auto update #30 2 * * 7 root PATH="$PATH:/usr/local/bin/" pihole updatePihole -# 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 +# Pi-hole: Flush the log daily at 00:00 # The flush script will use logrotate if available -00 00 * * * root PATH="$PATH:/usr/local/bin/" pihole flush once +# parameter "once": logrotate only once (default is twice) +# parameter "quiet": don't print messages +00 00 * * * root PATH="$PATH:/usr/local/bin/" pihole flush once quiet @reboot root /usr/sbin/logrotate /etc/pihole/logrotate From 1f3db8b6025e6f81b41d7d134ac07559ea6d8ead Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Thu, 18 May 2017 12:43:17 +1000 Subject: [PATCH 019/162] Confirm Tricorder is online * Scan port 9998 to confirm the availability of "tricorder.pi-hole.net" * Exit codes for upload process --- pihole | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pihole b/pihole index 11369ae1..3db64172 100755 --- a/pihole +++ b/pihole @@ -305,9 +305,15 @@ tricorderFunc() { echo "Please do not call Tricorder directly." exit 1 fi + + if ! timeout 2 nc -z tricorder.pi-hole.net 9998 &> /dev/null; then + echo "Unable to connect to Pi-hole's Tricorder server." + exit 1 + fi if command -v openssl &> /dev/null; then openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin + exit "$?" else echo "Your debug log will be transmitted unencrypted via plain-text" echo "There is a possibility that this could be intercepted by a third party" @@ -320,6 +326,7 @@ tricorderFunc() { done echo " " nc tricorder.pi-hole.net 9999 < /dev/stdin + exit "$?" fi } From a620a5c430f34e0c4bcd4ae906ee60aa982520bd Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Thu, 18 May 2017 12:53:32 +1000 Subject: [PATCH 020/162] Formatting consistency --- pihole | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pihole b/pihole index 3db64172..869db5ba 100755 --- a/pihole +++ b/pihole @@ -301,7 +301,7 @@ Branches: } tricorderFunc() { - if [ ! -p "/dev/stdin" ]; then + if [[ ! -p "/dev/stdin" ]]; then echo "Please do not call Tricorder directly." exit 1 fi @@ -319,7 +319,7 @@ tricorderFunc() { echo "There is a possibility that this could be intercepted by a third party" echo "If you wish to cancel, press Ctrl-C to exit within 10 seconds" secs="10" - while [ "$secs" -gt 0 ]; do + while [[ "$secs" -gt "0" ]]; do echo -ne "." sleep 1 : $((secs--)) From 69b41dd72e19e7ed490ce7233638b04d5bc2f4bd Mon Sep 17 00:00:00 2001 From: Mcat12 Date: Fri, 19 May 2017 11:16:34 -0400 Subject: [PATCH 021/162] Add link to Windows DNS Swapper See #1400 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 75c548e5..6f8813fa 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,7 @@ You can view [real-time stats](https://discourse.pi-hole.net/t/how-do-i-view-my- - [Let your blink1 device blink when Pi-hole filters ads](https://gist.github.com/elpatron68/ec0b4c582e5abf604885ac1e068d233f) - [Pi-hole Prometheus exporter](https://github.com/nlamirault/pihole_exporter): a [Prometheus](https://prometheus.io/) exporter for Pi-hole - [Pi-hole Droid - open source Android client](https://github.com/friimaind/pi-hole-droid) +- [Windows DNS Swapper](https://github.com/roots84/DNS-Swapper), see [#1400](https://github.com/pi-hole/pi-hole/issues/1400) ## Coverage From 6fa00e7cc86a8fb661ab3343c67b2d30e5d583f1 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 20 May 2017 01:34:13 -0500 Subject: [PATCH 022/162] first functions with pretty colors. check OS, setupVars, and contents of .d dirs --- advanced/Scripts/piholeDebug.sh | 622 +++++++------------------------- 1 file changed, 128 insertions(+), 494 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 8020cc80..8d57b085 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -9,7 +9,9 @@ # Please see LICENSE file for your rights under this license. - +# causes a pipeline to produce a failure return code if any command errors. +# Normally, pipelines only return a failure if the last command errors. +# In combination with set -e, this will make your script exit if any command in a pipeline errors. set -o pipefail ######## GLOBAL VARS ######## @@ -28,515 +30,147 @@ PIHOLEGITDIR="/etc/.pihole/" ADMINGITDIR="/var/www/html/admin/" WHITELISTMATCHES="/tmp/whitelistmatches.list" readonly FTLLOG="/var/log/pihole-FTL.log" +coltable=/opt/pihole/COL_TABLE -TIMEOUT=60 -# Header info and introduction -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 48 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 +if [[ -f ${coltable} ]]; then + source ${coltable} +else + COL_NC='\e[0m' # No Color + COL_YELLOW='\e[1;33m' + COL_LIGHT_PURPLE='\e[1;35m' + COL_CYAN='\e[0;36m' + TICK="[${COL_LIGHT_GREEN}✓${COL_NC}]" + CROSS="[${COL_LIGHT_RED}✗${COL_NC}]" + INFO="[i]" + DONE="${COL_LIGHT_GREEN} done!${COL_NC}" + OVER="\r\033[K" +fi -source ${VARSFILE} - -### Private functions exist here ### -log_write() { - echo "${@}" >&3 -} - -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 -} - -header_write() { - log_echo "" - log_echo "---= ${1}" - log_write "" -} - -file_parse() { - while read -r line; do - if [ ! -z "${line}" ]; then - [[ "${line}" =~ ^#.*$ || ! "${line}" || "${line}" == "WEBPASSWORD="* ]] && continue - log_write "${line}" - fi - done < "${1}" - log_write "" -} - -block_parse() { - log_write "${1}" -} - -lsof_parse() { - local user - local process - - 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." - - log_write "Found user ${user} with process ${process}" -} - - -version_check() { - header_write "Detecting Installed Package Versions:" - - local error_found - local pi_hole_ver - local pi_hole_branch - local pi_hole_commit - local admin_ver - local admin_branch - local admin_commit - local light_ver - local php_ver - local status - error_found=0 - - cd "${PIHOLEGITDIR}" &> /dev/null || \ - { status="Pi-hole git directory not found."; error_found=1; } - if git status &> /dev/null; then - pi_hole_ver=$(git describe --tags --abbrev=0) - pi_hole_branch=$(git rev-parse --abbrev-ref HEAD) - pi_hole_commit=$(git describe --long --dirty --tags --always) - log_echo -r "Pi-hole: ${pi_hole_ver:-Untagged} (${pi_hole_branch:-Detached}:${pi_hole_commit})" +echo_succes_or_fail() { + local message="${1}" + if [ $? -eq 0 ]; then + echo -e " ${TICK} ${message}" else - status=${status:-"Pi-hole repository damaged."} - error_found=1 - fi - if [[ "${status}" ]]; then - log_echo "${status}" - unset status + echo -e " ${CROSS} ${message}" fi +} - cd "${ADMINGITDIR}" || \ - { status="Pi-hole Dashboard git directory not found."; error_found=1; } - if git status &> /dev/null; then - admin_ver=$(git describe --tags --abbrev=0) - admin_branch=$(git rev-parse --abbrev-ref HEAD) - admin_commit=$(git describe --long --dirty --tags --always) - log_echo -r "Pi-hole Dashboard: ${admin_ver:-Untagged} (${admin_branch:-Detached}:${admin_commit})" +initiate_debug() { + # Clear the screen so the debug log is readable + clear + echo -e "${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC}" + echo -e " ${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initiated." +} + +# This is a function for visually displaying the curent test that is being run. +# Accepts one variable: the name of what is being diagnosed +echo_current_diagnostic() { + # Colors are used for visually distinguishing each test in the output + echo -e "\n${COL_LIGHT_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}" +} + +if_file_exists() { + local file_to_test="${1}" + # If the file is readable + if [[ -r "${file_to_test}" ]]; then + # Return success + return 0 else - status=${status:-"Pi-hole Dashboard repository damaged."} - error_found=1 - fi - if [[ "${status}" ]]; then - log_echo "${status}" - unset status + # Otherwise, return a failure + return 1 fi +} - if light_ver=$(lighttpd -v |& head -n1 | cut -d " " -f1); then - log_echo -r "${light_ver}" - else - log_echo "lighttpd not installed." - error_found=1 - fi - if php_ver=$(php -v |& head -n1); then - log_echo -r "${php_ver}" - else - log_echo "PHP not installed." - error_found=1 - fi +get_distro_attributes() { + # Put the current Internal Field Separator into another variable so it can be restored later + OLD_IFS="$IFS" + # Store the distro info in an array and make it global since the OS won't change, + # but we'll keep it within the function for better unit testing + IFS=$'\r\n' command eval 'distro_info=( $(cat /etc/*release) )' - return "${error_found}" + local distro_attribute + for distro_attribute in "${distro_info[@]}"; do + # Display the information with the ${INFO} icon + # No need to show the support URLs so they are grepped out + echo " ${INFO} ${distro_attribute}" | grep -v "_URL" | tr -d '"' + done + # Set the IFS back to what it was + IFS="$OLD_IFS" +} + +diagnose_operating_system() { + # Display the current test that is running + echo_current_diagnostic "Operating system" + + # If there is a /etc/*release file, it's probably a supported operating system, so we can + if_file_exists /etc/*release && \ + # display the attributes to the user + get_distro_attributes || \ + # If it doesn't exist, it's not a system we currently support + echo -e " ${CROSS} ${COL_LIGHT_RED}Distribution unknown -- most likely you are on an unsupported platform and may run into issues.${COL_NC} + ${INFO} ${COL_LIGHT_RED}Please see${COL_NC}: ${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273${COL_NC}" +} + +parse_file() { + local filename="${1}" + OLD_IFS="$IFS" + IFS=$'\r\n' command eval 'file_info=( $(cat "${filename}") )' + + local file_lines + for file_lines in "${file_info[@]}"; do + # Display the information with the ${INFO} icon + # No need to show the support URLs so they are grepped out + echo " ${INFO} ${file_lines}" + done + # Set the IFS back to what it was + IFS="$OLD_IFS" +} + +diagnose_setup_variables() { + # Display the current test that is running + echo_current_diagnostic "Setup variables" + + # If the variable file exists, + if_file_exists "${VARSFILE}" && \ + # source it + echo -e " ${INFO} Sourcing ${VARSFILE}..."; + source ${VARSFILE}; + # and display a green check mark with ${DONE} + echo_succes_or_fail "${VARSFILE} is readable and has been sourced." || \ + # Othwerwise, error out + echo_succes_or_fail "${VARSFILE} is not readable. + ${INFO} $(ls -l ${VARSFILE} 2>/dev/null)"; + parse_file "${VARSFILE}" } dir_check() { - header_write "Detecting contents of ${1}:" - for file in $1*; do - header_write "File ${file} found" - echo -n "::: Parsing..." - file_parse "${file}" - echo "done" - done - echo ":::" -} - -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 -n "::: File exists, parsing..." - file_parse "${search_file}" - echo "done" - 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 - return 0 - else - return 1 - fi -} - -ip_check() { - local protocol=${1} - local gravity=${2} - header_write "Checking IPv${protocol} Stack" - - local ip_addr_list="$(ip -${protocol} addr show dev ${PIHOLE_INTERFACE} | awk -F ' ' '{ for(i=1;i<=NF;i++) if ($i ~ '/^inet/') print $(i+1) }')" - if [[ -n ${ip_addr_list} ]]; then - log_write "IPv${protocol} on ${PIHOLE_INTERFACE}" - log_write "Gravity configured for: ${2:-NOT CONFIGURED}" - log_write "----" - log_write "${ip_addr_list}" - echo "::: IPv${protocol} addresses located on ${PIHOLE_INTERFACE}" - ip_ping_check ${protocol} - return $(( 0 + $? )) - else - log_echo "No IPv${protocol} found on ${PIHOLE_INTERFACE}" - return 1 - fi -} - -ip_ping_check() { - local protocol=${1} - local cmd - - if [[ ${protocol} == "6" ]]; then - cmd="ping6" - g_addr="2001:4860:4860::8888" - else - cmd="ping" - g_addr="8.8.8.8" - fi - - local ip_def_gateway=$(ip -${protocol} route | grep default | cut -d ' ' -f 3) - if [[ -n ${ip_def_gateway} ]]; then - echo -n "::: Pinging default IPv${protocol} gateway: " - if ! ping_gateway="$(${cmd} -q -W 3 -c 3 -n ${ip_def_gateway} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then - log_echo "Gateway did not respond." - return 1 - else - log_echo "Gateway responded." - log_write "${ping_gateway}" - fi - echo -n "::: Pinging Internet via IPv${protocol}: " - if ! ping_inet="$(${cmd} -q -W 3 -c 3 -n ${g_addr} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then - log_echo "Query did not respond." - return 1 - else - log_echo "Query responded." - log_write "${ping_inet}" - fi - else - log_echo " No gateway detected." - fi - return 0 -} - -port_check() { - local lsof_value - - lsof_value=$(lsof -i ${1}:${2} -FcL | tr '\n' ' ') \ - && lsof_parse "${lsof_value}" "${3}" \ - || log_echo "Failure: IPv${1} Port not in use" -} - -daemon_check() { - # Check for daemon ${1} on port ${2} - header_write "Daemon Process Information" - - echo "::: Checking ${2} port for ${1} listener." - - if [[ ${IPV6_READY} ]]; then - port_check 6 "${2}" "${1}" - fi - lsof_value=$(lsof -i 4:${2} -FcL | tr '\n' ' ') \ - port_check 4 "${2}" "${1}" -} - -testResolver() { - local protocol="${1}" - header_write "Resolver Functions Check (IPv${protocol})" - local IP="${2}" - local g_addr - local l_addr - local url - local testurl - local localdig - local piholedig - local remotedig - - if [[ ${protocol} == "6" ]]; then - g_addr="2001:4860:4860::8888" - l_addr="::1" - r_type="AAAA" - else - g_addr="8.8.8.8" - l_addr="127.0.0.1" - r_type="A" - fi - - # Find a blocked url that has not been whitelisted. - url=$(shuf -n 1 "${GRAVITYFILE}" | awk -F ' ' '{ print $2 }') - - testurl="${url:-doubleclick.com}" - - - log_write "Resolution of ${testurl} from Pi-hole (${l_addr}):" - if localdig=$(dig -"${protocol}" "${testurl}" @${l_addr} +short "${r_type}"); then - log_write "${localdig}" - else - log_write "Failed to resolve ${testurl} on Pi-hole (${l_addr})" - fi - log_write "" - - log_write "Resolution of ${testurl} from Pi-hole (${IP}):" - if piholedig=$(dig -"${protocol}" "${testurl}" @"${IP}" +short "${r_type}"); then - log_write "${piholedig}" - else - log_write "Failed to resolve ${testurl} on Pi-hole (${IP})" - fi - log_write "" - - - log_write "Resolution of ${testurl} from ${g_addr}:" - if remotedig=$(dig -"${protocol}" "${testurl}" @${g_addr} +short "${r_type}"); then - log_write "${remotedig:-NXDOMAIN}" - else - log_write "Failed to resolve ${testurl} on upstream server ${g_addr}" - fi - log_write "" -} - -testChaos(){ - # Check Pi-hole specific records - - log_write "Pi-hole dnsmasq specific records lookups" - log_write "Cache Size:" - log_write $(dig +short chaos txt cachesize.bind) - log_write "Upstream Servers:" - log_write $(dig +short chaos txt servers.bind) - log_write "" - -} -checkProcesses() { - header_write "Processes Check" - - echo "::: Logging status of lighttpd, dnsmasq and pihole-FTL..." - PROCESSES=( lighttpd dnsmasq pihole-FTL ) - for i in "${PROCESSES[@]}"; do - log_write "Status for ${i} daemon:" - log_write $(systemctl is-active "${i}") - done - log_write "" -} - -debugLighttpd() { - echo "::: Checking for necessary lighttpd files." - files_check "${LIGHTTPDFILE}" - files_check "${LIGHTTPDERRFILE}" - echo ":::" -} - -countdown() { - local tuvix - tuvix=${TIMEOUT} - printf "::: Logging will automatically teminate in %s seconds\n" "${TIMEOUT}" - while [ $tuvix -ge 1 ] - do - printf ":::\t%s seconds left. " "${tuvix}" - if [[ -z "${WEBCALL}" ]]; then - printf "\r" - else - printf "\n" - fi - sleep 5 - tuvix=$(( tuvix - 5 )) + local directory="${1}" + echo_current_diagnostic "contents of ${directory}" + for filename in "${directory}"*; do + if_file_exists "${filename}" && \ + echo_succes_or_fail "Files detected" || \ + echo_succes_or_fail "directory does not exist" done } -# Continuously append the pihole.log file to the pihole_debug.log file -dumpPiHoleLog() { - trap '{ echo -e "\n::: Finishing debug write from interrupt... Quitting!" ; exit 1; }' INT - 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 - # Dummy process to use for flagging down tail to terminate - countdown & - tail -n0 -f --pid=$! "${PIHOLELOG}" >&4 - else - log_write "No pihole.log file found!" - printf ":::\tNo pihole.log file found!\n" - fi +list_files_in_dir() { + local dir_to_parse="${1}" + local filename + files_found=( $(ls "${dir_to_parse}") ) + for each_file in "${files_found[@]}"; do + # Display the information with the ${INFO} icon + echo " ${INFO} ${each_file}" + done + } -# Anything to be done after capturing of pihole.log terminates -finalWork() { - local tricorder - echo "::: Finshed debugging!" - - # Ensure the file exists, create if not, clear if exists. - truncate --size=0 "${DEBUG_LOG}" - chmod 644 ${DEBUG_LOG} - chown "$USER":pihole ${DEBUG_LOG} - # copy working temp file to final log location - cat /proc/$$/fd/3 >> "${DEBUG_LOG}" - # Straight dump of tailing the logs, can sanitize later if needed. - cat /proc/$$/fd/4 >> "${DEBUG_LOG}" - - echo "::: The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." - if [[ "${AUTOMATED}" ]]; then - echo "::: Debug script running in automated mode, uploading log to tricorder..." - tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999) - else - 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 - fi - # Check if tricorder.pi-hole.net is reachable and provide token. - if [ -n "${tricorder}" ]; then - echo "::: ---=== Your debug token is : ${tricorder} Please make a note of it. ===---" - echo "::: Contact the Pi-hole team with your token for assistance." - echo "::: Thank you." - else - echo "::: There was an error uploading your debug log." - echo "::: Please try again or contact the Pi-hole team for assistance." - fi - echo "::: A local copy of the Debug log can be found at : /var/log/pihole_debug.log" +check_dnsmasq_d() { + local directory=/etc/dnsmasq.d + dir_check "${directory}" + list_files_in_dir "${directory}" } -### END FUNCTIONS ### -# Create temporary file for log -TEMPLOG=$(mktemp /tmp/pihole_temp.XXXXXX) -# Open handle 3 for templog -exec 3>"$TEMPLOG" -# Delete templog, but allow for addressing via file handle. -rm "$TEMPLOG" - -# Create temporary file for logdump using file handle 4 -DUMPLOG=$(mktemp /tmp/pihole_temp.XXXXXX) -exec 4>"$DUMPLOG" -rm "$DUMPLOG" - -# 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 6 ${IPV6_ADDRESS} -ip_check 4 ${IPV4_ADDRESS} - -daemon_check lighttpd http -daemon_check dnsmasq domain -daemon_check pihole-FTL 4711 -checkProcesses - -# Check local/IP/Google for IPv4 Resolution -testResolver 4 "${IPV4_ADDRESS%/*}" -# If IPv6 enabled, check resolution -if [[ "${IPV6_ADDRESS}" ]]; then - testResolver 6 "${IPV6_ADDRESS%/*}" -fi -# Poll dnsmasq Pi-hole specific queries -testChaos - -debugLighttpd - -files_check "${DNSMASQFILE}" -dir_check "${DNSMASQCONFDIR}" -files_check "${WHITELISTFILE}" -files_check "${BLACKLISTFILE}" -files_check "${ADLISTFILE}" - - -header_write "Analyzing gravity.list" - - gravity_length=$(grep -c ^ "${GRAVITYFILE}") \ - && log_write "${GRAVITYFILE} is ${gravity_length} lines long." \ - || log_echo "Warning: No gravity.list file found!" - -header_write "Analyzing pihole.log" - - pihole_length=$(grep -c ^ "${PIHOLELOG}") \ - && log_write "${PIHOLELOG} is ${pihole_length} lines long." \ - || log_echo "Warning: No pihole.log file found!" - - pihole_size=$(du -h "${PIHOLELOG}" | awk '{ print $1 }') \ - && log_write "${PIHOLELOG} is ${pihole_size}." \ - || log_echo "Warning: No pihole.log file found!" - -header_write "Analyzing pihole-FTL.log" - - FTL_length=$(grep -c ^ "${FTLLOG}") \ - && log_write "${FTLLOG} is ${FTL_length} lines long." \ - || log_echo "Warning: No pihole-FTL.log file found!" - - FTL_size=$(du -h "${FTLLOG}" | awk '{ print $1 }') \ - && log_write "${FTLLOG} is ${FTL_size}." \ - || log_echo "Warning: No pihole-FTL.log file found!" - -tail -n50 "${FTLLOG}" >&3 - -trap finalWork EXIT - -### Method calls for additional logging ### -dumpPiHoleLog +initiate_debug +diagnose_operating_system +diagnose_setup_variables +check_dnsmasq_d From 5d7ef9281f3b7ee02070e3bb8797da4bc97007ca Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 20 May 2017 02:01:56 -0500 Subject: [PATCH 023/162] get just the OS pretty name for Dan --- advanced/Scripts/piholeDebug.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 8d57b085..c89218b6 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -90,9 +90,14 @@ get_distro_attributes() { local distro_attribute for distro_attribute in "${distro_info[@]}"; do - # Display the information with the ${INFO} icon - # No need to show the support URLs so they are grepped out - echo " ${INFO} ${distro_attribute}" | grep -v "_URL" | tr -d '"' + # Display the information with the ${INFO} icon (we need just the OS PRETTY_NAME) + pretty_name_key=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f1) + if [[ "${pretty_name_key}" == "PRETTY_NAME" ]]; then + PRETTY_NAME=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f2- | tr -d '"') + echo " ${INFO} ${PRETTY_NAME}" + else + : + fi done # Set the IFS back to what it was IFS="$OLD_IFS" From c655e6ea7343ffb1bce2f813c4e38f5c5fc6eac4 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 20 May 2017 15:47:51 +0200 Subject: [PATCH 024/162] Install loopback firewall rules for FTL (#1419) * Install loopback firewall rules for FTL * FirewallD FTL ports Signed-off-by: Dan Schaper * Remove firewallD FTL local rules. Local rules should not be blocked in firewallD, not requred for internal service FTD> * Reinstate https rules, and delete FTL rules Fixes earlier commit. --- automated install/basic-install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index 7d5a5d0e..a2aff252 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -980,6 +980,7 @@ configureFirewall() { iptables -C INPUT -p tcp -m tcp --dport 80 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT iptables -C INPUT -p tcp -m tcp --dport 53 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT iptables -C INPUT -p udp -m udp --dport 53 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT + iptables -C INPUT -p tcp -m tcp --dport 4711:4720 -i lo -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 4711:4720 -i lo -j ACCEPT return 0 fi else From 2ef87ad110f849dce59a3f3dd336fb35e459ce5b Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Mon, 22 May 2017 06:47:26 +1000 Subject: [PATCH 025/162] Retrieve local repos on repair (#1481) * Retrieve local repos on repair * Change conditional to check for repair * Change wording of Update/Reconfigure message * Fixed indenting * Perform "git reset --hard" on reconfigure --- automated install/basic-install.sh | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index a2aff252..5d893067 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -1180,22 +1180,23 @@ update_dialogs() { } clone_or_update_repos() { -if [[ "${reconfigure}" == true ]]; then - echo "::: --reconfigure passed to install script. Not downloading/updating local repos" - else - # Get Git files for Core and Admin - getGitFiles ${PI_HOLE_LOCAL_REPO} ${piholeGitUrl} || \ - { echo "!!! Unable to clone ${piholeGitUrl} into ${PI_HOLE_LOCAL_REPO}, unable to continue."; \ - exit 1; \ - } + if [[ "${reconfigure}" == true ]]; then + echo "::: --reconfigure passed to install script. Resetting changes to local repos" + git reset --hard + else + # Get Git files for Core and Admin + getGitFiles ${PI_HOLE_LOCAL_REPO} ${piholeGitUrl} || \ + { echo "!!! Unable to clone ${piholeGitUrl} into ${PI_HOLE_LOCAL_REPO}, unable to continue."; \ + exit 1; \ + } - if [[ ${INSTALL_WEB} == true ]]; then - getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl} || \ - { echo "!!! Unable to clone ${webInterfaceGitUrl} into ${webInterfaceDir}, unable to continue."; \ - exit 1; \ - } - fi + if [[ ${INSTALL_WEB} == true ]]; then + getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl} || \ + { echo "!!! Unable to clone ${webInterfaceGitUrl} into ${webInterfaceDir}, unable to continue."; \ + exit 1; \ + } fi + fi } FTLinstall() { From 69fe889f92904ed73a02f75f01be80111cf9fe67 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sun, 21 May 2017 23:25:53 -0500 Subject: [PATCH 026/162] comments for all lines and small formatting changes --- advanced/Scripts/piholeDebug.sh | 62 +++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index c89218b6..faf68fb9 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -47,11 +47,15 @@ else fi echo_succes_or_fail() { + # Set the first argument passed to tihs function as a named variable for better readability local message="${1}" + # If the command was successful (a zero), if [ $? -eq 0 ]; then - echo -e " ${TICK} ${message}" + # show success + echo -e " ${TICK} ${message}" else - echo -e " ${CROSS} ${message}" + # Otherwise, show a error + echo -e " ${CROSS} ${message}" fi } @@ -59,17 +63,20 @@ initiate_debug() { # Clear the screen so the debug log is readable clear echo -e "${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC}" - echo -e " ${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initiated." + # Timestamp the start of the log + echo -e " ${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initiated." } # This is a function for visually displaying the curent test that is being run. # Accepts one variable: the name of what is being diagnosed +# Colors do not show in the dasboard, but the icons do: [i], [✓], and [✗] echo_current_diagnostic() { # Colors are used for visually distinguishing each test in the output echo -e "\n${COL_LIGHT_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}" } if_file_exists() { + # Set the first argument passed to tihs function as a named variable for better readability local file_to_test="${1}" # If the file is readable if [[ -r "${file_to_test}" ]]; then @@ -88,13 +95,17 @@ get_distro_attributes() { # but we'll keep it within the function for better unit testing IFS=$'\r\n' command eval 'distro_info=( $(cat /etc/*release) )' + # Set a named variable for better readability local distro_attribute + # For each line found in an /etc/*release file, for distro_attribute in "${distro_info[@]}"; do - # Display the information with the ${INFO} icon (we need just the OS PRETTY_NAME) + # display the information with the ${INFO} icon pretty_name_key=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f1) + # we need just the OS PRETTY_NAME, so print it when we find it if [[ "${pretty_name_key}" == "PRETTY_NAME" ]]; then PRETTY_NAME=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f2- | tr -d '"') - echo " ${INFO} ${PRETTY_NAME}" + echo " ${INFO} ${PRETTY_NAME}" + # Otherwise, do nothing else : fi @@ -104,6 +115,8 @@ get_distro_attributes() { } diagnose_operating_system() { + local faq_url="https://discourse.pi-hole.net/t/hardware-software-requirements/273" + local error_msg="Distribution unknown -- most likely you are on an unsupported platform and may run into issues." # Display the current test that is running echo_current_diagnostic "Operating system" @@ -111,21 +124,25 @@ diagnose_operating_system() { if_file_exists /etc/*release && \ # display the attributes to the user get_distro_attributes || \ - # If it doesn't exist, it's not a system we currently support - echo -e " ${CROSS} ${COL_LIGHT_RED}Distribution unknown -- most likely you are on an unsupported platform and may run into issues.${COL_NC} - ${INFO} ${COL_LIGHT_RED}Please see${COL_NC}: ${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273${COL_NC}" + # If it doesn't exist, it's not a system we currently support and link to FAQ + echo -e " ${CROSS} ${COL_LIGHT_RED}${error_msg}${COL_NC} + ${INFO} ${COL_LIGHT_RED}Please see${COL_NC}: ${COL_CYAN}${faq_url}${COL_NC}" } parse_file() { + # Set the first argument passed to tihs function as a named variable for better readability local filename="${1}" + # Put the current Internal Field Separator into another variable so it can be restored later OLD_IFS="$IFS" + # Get the lines that are in the file(s) and store them in an array for parsing later IFS=$'\r\n' command eval 'file_info=( $(cat "${filename}") )' + # Set a named variable for better readability local file_lines + # For each lin in the file, for file_lines in "${file_info[@]}"; do - # Display the information with the ${INFO} icon - # No need to show the support URLs so they are grepped out - echo " ${INFO} ${file_lines}" + # display the information with the ${INFO} icon + echo " ${INFO} ${file_lines}" done # Set the IFS back to what it was IFS="$OLD_IFS" @@ -138,40 +155,55 @@ diagnose_setup_variables() { # If the variable file exists, if_file_exists "${VARSFILE}" && \ # source it - echo -e " ${INFO} Sourcing ${VARSFILE}..."; + echo -e " ${INFO} Sourcing ${VARSFILE}..."; source ${VARSFILE}; # and display a green check mark with ${DONE} echo_succes_or_fail "${VARSFILE} is readable and has been sourced." || \ # Othwerwise, error out echo_succes_or_fail "${VARSFILE} is not readable. - ${INFO} $(ls -l ${VARSFILE} 2>/dev/null)"; + ${INFO} $(ls -l ${VARSFILE} 2>/dev/null)"; parse_file "${VARSFILE}" } +# This function can check a directory exists +# Pi-hole has files in several places, so we will reuse this function dir_check() { + # Set the first argument passed to tihs function as a named variable for better readability local directory="${1}" + # Display the current test that is running echo_current_diagnostic "contents of ${directory}" + # For each file in the directory, for filename in "${directory}"*; do + # check if exists first; if it does, if_file_exists "${filename}" && \ + # show a success message echo_succes_or_fail "Files detected" || \ + # Otherwise, show an error echo_succes_or_fail "directory does not exist" done } list_files_in_dir() { + # Set the first argument passed to tihs function as a named variable for better readability local dir_to_parse="${1}" + # Set another local variable for better readability local filename + # Store the files found in an array files_found=( $(ls "${dir_to_parse}") ) + # For each file in the arry, for each_file in "${files_found[@]}"; do - # Display the information with the ${INFO} icon - echo " ${INFO} ${each_file}" + # display the information with the ${INFO} icon + echo " ${INFO} ${each_file}" done } check_dnsmasq_d() { + # Set a local variable for better readability local directory=/etc/dnsmasq.d + # Check if the directory exists dir_check "${directory}" + # if it does, list the files in it list_files_in_dir "${directory}" } From 1aa5943e67d8237344538074990556d5a3522319 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 22 May 2017 01:06:15 -0500 Subject: [PATCH 027/162] add if directory exists function --- advanced/Scripts/piholeDebug.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index faf68fb9..9da749e7 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -88,6 +88,19 @@ if_file_exists() { fi } +if_directory_exists() { + # Set the first argument passed to tihs function as a named variable for better readability + local directory_to_test="${1}" + # If the file is readable + if [[ -d "${directory_to_test}" ]]; then + # Return success + return 0 + else + # Otherwise, return a failure + return 1 + fi +} + get_distro_attributes() { # Put the current Internal Field Separator into another variable so it can be restored later OLD_IFS="$IFS" From 6c4a7b626ec9e6286c97ccafd43cbe50a8b459a4 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 22 May 2017 02:39:00 -0500 Subject: [PATCH 028/162] add pihole version check functions --- advanced/Scripts/piholeDebug.sh | 53 ++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 9da749e7..71d59d39 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -75,7 +75,7 @@ echo_current_diagnostic() { echo -e "\n${COL_LIGHT_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}" } -if_file_exists() { +file_exists() { # Set the first argument passed to tihs function as a named variable for better readability local file_to_test="${1}" # If the file is readable @@ -101,6 +101,48 @@ if_directory_exists() { fi } +check_core_version() { + echo_current_diagnostic "Pi-hole Versions" + local error_msg="git status failed" + if_directory_exists "${PIHOLEGITDIR}" && \ + cd "${PIHOLEGITDIR}" || \ + echo "pihole repo does not exist" + if git status &> /dev/null; then + PI_HOLE_VERSION=$(git describe --tags --abbrev=0); + PI_HOLE_BRANCH=$(git rev-parse --abbrev-ref HEAD); + PI_HOLE_COMMIT=$(git describe --long --dirty --tags --always) + echo -e " ${INFO} Core: ${PI_HOLE_VERSION} + ${INFO} Branch: ${PI_HOLE_BRANCH} + ${INFO} Commit: ${PI_HOLE_COMMIT}" + else + echo "${error_msg}" + return 1 + fi +} + +check_web_version() { + local error_msg="git status failed" + if_directory_exists "${ADMINGITDIR}" && \ + cd "${ADMINGITDIR}" || \ + echo "repo does not exist" + if git status &> /dev/null; then + WEB_VERSION=$(git describe --tags --abbrev=0); + WEB_BRANCH=$(git rev-parse --abbrev-ref HEAD); + WEB_COMMIT=$(git describe --long --dirty --tags --always) + echo -e " ${INFO} Web: ${WEB_VERSION} + ${INFO} Branch: ${WEB_BRANCH} + ${INFO} Commit: ${WEB_COMMIT}" + else + echo "${error_msg}" + return 1 + fi +} + +check_ftl_version() { + FTL_VERSION=$(pihole-FTL version) + echo -e " ${INFO} FTL: ${FTL_VERSION}" +} + get_distro_attributes() { # Put the current Internal Field Separator into another variable so it can be restored later OLD_IFS="$IFS" @@ -134,7 +176,7 @@ diagnose_operating_system() { echo_current_diagnostic "Operating system" # If there is a /etc/*release file, it's probably a supported operating system, so we can - if_file_exists /etc/*release && \ + file_exists /etc/*release && \ # display the attributes to the user get_distro_attributes || \ # If it doesn't exist, it's not a system we currently support and link to FAQ @@ -166,7 +208,7 @@ diagnose_setup_variables() { echo_current_diagnostic "Setup variables" # If the variable file exists, - if_file_exists "${VARSFILE}" && \ + file_exists "${VARSFILE}" && \ # source it echo -e " ${INFO} Sourcing ${VARSFILE}..."; source ${VARSFILE}; @@ -188,7 +230,7 @@ dir_check() { # For each file in the directory, for filename in "${directory}"*; do # check if exists first; if it does, - if_file_exists "${filename}" && \ + file_exists "${filename}" && \ # show a success message echo_succes_or_fail "Files detected" || \ # Otherwise, show an error @@ -221,6 +263,9 @@ check_dnsmasq_d() { } initiate_debug +check_core_version +check_web_version +check_ftl_version diagnose_operating_system diagnose_setup_variables check_dnsmasq_d From daff5d8b5a21182fa86f75d4c325afdfeb8697b6 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 22 May 2017 03:05:51 -0500 Subject: [PATCH 029/162] add critical dependencies version check functions --- advanced/Scripts/piholeDebug.sh | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 71d59d39..d1f49f7c 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -143,6 +143,34 @@ check_ftl_version() { echo -e " ${INFO} FTL: ${FTL_VERSION}" } +check_web_server_version() { + WEB_SERVER="lighttpd" + WEB_SERVER_VERSON="$(lighttpd -v |& head -n1 | cut -d '/' -f2 | cut -d ' ' -f1)" + echo -e " ${INFO} ${WEB_SERVER}" + if [[ -z "${WEB_SERVER_VERSON}" ]]; then + echo -e " ${CROSS} ${WEB_SERVER} version could not be detected." + else + echo -e " ${TICK} ${WEB_SERVER_VERSON}" + fi +} + +check_resolver_version() { + RESOLVER="dnsmasq" + RESOVLER_VERSON="$(dnsmasq -v |& head -n1 | awk '{print $3}')" + echo -e " ${INFO} ${RESOLVER}" + if [[ -z "${RESOVLER_VERSON}" ]]; then + echo -e " ${CROSS} ${RESOLVER} version could not be detected." + else + echo -e " ${TICK} ${RESOVLER_VERSON}" + fi +} + +check_critical_dependencies() { + echo_current_diagnostic "Versions of critical dependencies" + check_web_server_version + check_web_server_version +} + get_distro_attributes() { # Put the current Internal Field Separator into another variable so it can be restored later OLD_IFS="$IFS" @@ -267,5 +295,6 @@ check_core_version check_web_version check_ftl_version diagnose_operating_system +check_critical_dependencies diagnose_setup_variables check_dnsmasq_d From 8c5c1316dd83295bbb196d218faed5ec80403b55 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 22 May 2017 08:48:56 -0500 Subject: [PATCH 030/162] add php version and processor check functions --- advanced/Scripts/piholeDebug.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index d1f49f7c..50db8a97 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -165,10 +165,22 @@ check_resolver_version() { fi } +check_php_version() { + PHP_VERSION=$(php -v |& head -n1 | cut -d '-' -f1 | cut -d ' ' -f2) + echo -e " ${INFO} PHP" + if [[ -z "${PHP_VERSION}" ]]; then + echo -e " ${CROSS} PHP version could not be detected." + else + echo -e " ${TICK} ${PHP_VERSION}" + fi + +} + check_critical_dependencies() { echo_current_diagnostic "Versions of critical dependencies" check_web_server_version check_web_server_version + check_php_version } get_distro_attributes() { @@ -212,6 +224,16 @@ diagnose_operating_system() { ${INFO} ${COL_LIGHT_RED}Please see${COL_NC}: ${COL_CYAN}${faq_url}${COL_NC}" } +processor_check() { + echo_current_diagnostic "Processor" + PROCESSOR=$(uname -m) + if [[ -z "${PROCESSOR}" ]]; then + echo -e " ${CROSS} Processor could not be identified." + else + echo -e " ${INFO} ${PROCESSOR}" + fi +} + parse_file() { # Set the first argument passed to tihs function as a named variable for better readability local filename="${1}" @@ -295,6 +317,7 @@ check_core_version check_web_version check_ftl_version diagnose_operating_system +processor_check check_critical_dependencies diagnose_setup_variables check_dnsmasq_d From 8fd9a22d18c36f429a9bfa3e79f05e26e5c027b7 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 22 May 2017 12:05:42 -0500 Subject: [PATCH 031/162] add detect IP function --- advanced/Scripts/piholeDebug.sh | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 50db8a97..e13bff0f 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -228,9 +228,34 @@ processor_check() { echo_current_diagnostic "Processor" PROCESSOR=$(uname -m) if [[ -z "${PROCESSOR}" ]]; then - echo -e " ${CROSS} Processor could not be identified." + echo -e " ${CROSS} Processor could not be identified." else - echo -e " ${INFO} ${PROCESSOR}" + echo -e " ${INFO} ${PROCESSOR}" + fi +} + +detect_ip_addresses() { + # First argument should be a 4 or a 6 + local protocol=${1} + # Use ip to show the addresses for the chosen protocol + # Store the values in an arry so they can be looped through + # Get the lines that are in the file(s) and store them in an array for parsing later + declare -a ip_addr_list=( $(ip -${protocol} addr show dev ${PIHOLE_INTERFACE} | awk -F ' ' '{ for(i=1;i<=NF;i++) if ($i ~ '/^inet/') print $(i+1) }') ) + + # If there is something in the IP address list, + if [[ -n ${ip_addr_list} ]]; then + # Local iterator + local i + echo -e " ${INFO} IPv${protocol}" + # display the contents to the user + echo -e " ${INFO} Interface: ${PIHOLE_INTERFACE}" + for i in "${ip_addr_list[@]}"; do + echo -e " ${INFO} $i" + done + # Othwerwise explain that the protocol is not configured + else + echo -e " ${CROSS} No IPv${protocol} found on ${PIHOLE_INTERFACE}" + return 1 fi } @@ -260,8 +285,8 @@ diagnose_setup_variables() { # If the variable file exists, file_exists "${VARSFILE}" && \ # source it - echo -e " ${INFO} Sourcing ${VARSFILE}..."; source ${VARSFILE}; + echo -e " ${INFO} Sourcing ${VARSFILE}..."; # and display a green check mark with ${DONE} echo_succes_or_fail "${VARSFILE} is readable and has been sourced." || \ # Othwerwise, error out @@ -316,8 +341,8 @@ initiate_debug check_core_version check_web_version check_ftl_version +diagnose_setup_variables diagnose_operating_system processor_check check_critical_dependencies -diagnose_setup_variables check_dnsmasq_d From 107babe8f4578bacc436c4fc519eb31fafc1fff3 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 22 May 2017 12:35:57 -0500 Subject: [PATCH 032/162] add ping gateway function --- advanced/Scripts/piholeDebug.sh | 63 +++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index e13bff0f..b47d0203 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -246,19 +246,69 @@ detect_ip_addresses() { if [[ -n ${ip_addr_list} ]]; then # Local iterator local i - echo -e " ${INFO} IPv${protocol}" - # display the contents to the user - echo -e " ${INFO} Interface: ${PIHOLE_INTERFACE}" - for i in "${ip_addr_list[@]}"; do - echo -e " ${INFO} $i" + echo -e " ${TICK} IPv${protocol} on ${PIHOLE_INTERFACE}" + for i in "${!ip_addr_list[@]}"; do + echo -e " [$i] ${ip_addr_list[$i]}" done # Othwerwise explain that the protocol is not configured else - echo -e " ${CROSS} No IPv${protocol} found on ${PIHOLE_INTERFACE}" + echo -e " ${CROSS} No IPv${protocol} found on ${PIHOLE_INTERFACE}" return 1 fi } + +ping_gateway() { + # First argument should be a 4 or a 6 + local protocol="${1}" + # If the protocol is 6, + if [[ ${protocol} == "6" ]]; then + # use ping6 + local cmd="ping6" + # and Google's public IPv6 address + local public_address="2001:4860:4860::8888" + # Otherwise, + else + # use ping + local cmd="ping" + # and Google's public IPv4 address + local public_address="8.8.8.8" + fi + + # Find the default gateway using IPv4 or IPv6 + local gateway + gateway="$(ip -${protocol} route | grep default | cut -d ' ' -f 3)" + + # If the gateway variable has a value (meaning a gateway was found), + if [[ -n "${gateway}" ]]; then + # Let the user know we will ping the gateway for a response + echo -e " ${INFO} Trying three pings on IPv${protocol} gateway at ${gateway}..." + # Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only, + # on the pihole interface, and tail the last three lines of the output + # If pinging the gateway is not successful, + if ! ping_cmd="$(${cmd} -q -c 3 -W 3 -n ${gateway} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then + # let the user know + echo -e " ${CROSS} Gateway did not respond." + # and return an error code + return 1 + # Otherwise, + else + # show a success + echo -e " ${TICK} Gateway responded." + # and return a success code + return 0 + fi + fi +} + +check_networking() { + echo_current_diagnostic "Networking" + detect_ip_addresses "4" + ping_gateway "4" + detect_ip_addresses "6" + ping_gateway "6" +} + parse_file() { # Set the first argument passed to tihs function as a named variable for better readability local filename="${1}" @@ -344,5 +394,6 @@ check_ftl_version diagnose_setup_variables diagnose_operating_system processor_check +check_networking check_critical_dependencies check_dnsmasq_d From b74300f67cfb9ae356250b96deeb2dbfef787087 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 22 May 2017 12:57:55 -0500 Subject: [PATCH 033/162] add ping internet function and fix some spacing issues --- advanced/Scripts/piholeDebug.sh | 37 +++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index b47d0203..634e2ffa 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -148,9 +148,9 @@ check_web_server_version() { WEB_SERVER_VERSON="$(lighttpd -v |& head -n1 | cut -d '/' -f2 | cut -d ' ' -f1)" echo -e " ${INFO} ${WEB_SERVER}" if [[ -z "${WEB_SERVER_VERSON}" ]]; then - echo -e " ${CROSS} ${WEB_SERVER} version could not be detected." + echo -e " ${CROSS} ${WEB_SERVER} version could not be detected." else - echo -e " ${TICK} ${WEB_SERVER_VERSON}" + echo -e " ${TICK} ${WEB_SERVER_VERSON}" fi } @@ -159,9 +159,9 @@ check_resolver_version() { RESOVLER_VERSON="$(dnsmasq -v |& head -n1 | awk '{print $3}')" echo -e " ${INFO} ${RESOLVER}" if [[ -z "${RESOVLER_VERSON}" ]]; then - echo -e " ${CROSS} ${RESOLVER} version could not be detected." + echo -e " ${CROSS} ${RESOLVER} version could not be detected." else - echo -e " ${TICK} ${RESOVLER_VERSON}" + echo -e " ${TICK} ${RESOVLER_VERSON}" fi } @@ -169,9 +169,9 @@ check_php_version() { PHP_VERSION=$(php -v |& head -n1 | cut -d '-' -f1 | cut -d ' ' -f2) echo -e " ${INFO} PHP" if [[ -z "${PHP_VERSION}" ]]; then - echo -e " ${CROSS} PHP version could not be detected." + echo -e " ${CROSS} PHP version could not be detected." else - echo -e " ${TICK} ${PHP_VERSION}" + echo -e " ${TICK} ${PHP_VERSION}" fi } @@ -301,6 +301,31 @@ ping_gateway() { fi } +ping_internet() { + local protocol="${1}" + # If the protocol is 6, + if [[ ${protocol} == "6" ]]; then + # use ping6 + local cmd="ping6" + # and Google's public IPv6 address + local public_address="2001:4860:4860::8888" + # Otherwise, + else + # use ping + local cmd="ping" + # and Google's public IPv4 address + local public_address="8.8.8.8" + fi + echo -n " ${INFO} Trying three pings on IPv${protocol} to reach the Internet..." + if ! ping_inet="$(${cmd} -q -W 3 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then + echo -e " ${CROSS} Cannot reach the Internet" + return 1 + else + echo -e " ${TICK} Query responded." + return 0 + fi +} + check_networking() { echo_current_diagnostic "Networking" detect_ip_addresses "4" From 74eb8c8622ef701aad3d509bf88d9d7e3c6ceb40 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 22 May 2017 23:43:52 +0200 Subject: [PATCH 034/162] Change directory before trying to reset repository. Fixes #1489 --- automated install/basic-install.sh | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index 5d893067..2f4459d4 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -220,6 +220,19 @@ getGitFiles() { return 0 } +resetRepo() { + local directory="${1}" + local curdir + + curdir="${PWD}" + cd "${directory}" &> /dev/null || return 1 + echo -n "::: Resetting repo in ${1}..." + git reset --hard &> /dev/null || return $? + echo " done!" + cd "${curdir}" &> /dev/null || return 1 + return 0 +} + find_IPv4_information() { local route # Find IP used to route to outside world @@ -1182,7 +1195,16 @@ update_dialogs() { clone_or_update_repos() { if [[ "${reconfigure}" == true ]]; then echo "::: --reconfigure passed to install script. Resetting changes to local repos" - git reset --hard + resetRepo ${PI_HOLE_LOCAL_REPO} || \ + { echo "!!! Unable to reset ${PI_HOLE_LOCAL_REPO}, unable to continue."; \ + exit 1; \ + } + if [[ ${INSTALL_WEB} == true ]]; then + resetRepo ${webInterfaceDir} || \ + { echo "!!! Unable to reset ${webInterfaceDir}, unable to continue."; \ + exit 1; \ + } + fi else # Get Git files for Core and Admin getGitFiles ${PI_HOLE_LOCAL_REPO} ${piholeGitUrl} || \ From 5004cf331abf54a80c12109ecc5f8f80538686f5 Mon Sep 17 00:00:00 2001 From: Dan Schaper Date: Mon, 22 May 2017 15:36:51 -0700 Subject: [PATCH 035/162] No need to `cd $PWD` as it doesn't affect flow of caller script. Signed-off-by: Dan Schaper --- automated install/basic-install.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index 2f4459d4..ebf93f4a 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -222,14 +222,11 @@ getGitFiles() { resetRepo() { local directory="${1}" - local curdir - curdir="${PWD}" cd "${directory}" &> /dev/null || return 1 echo -n "::: Resetting repo in ${1}..." git reset --hard &> /dev/null || return $? echo " done!" - cd "${curdir}" &> /dev/null || return 1 return 0 } From 3035c9a366e2816397df3ab85e7abc8f2418cee3 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Tue, 23 May 2017 10:44:11 +0200 Subject: [PATCH 036/162] Refine output of password status in basic-install.sh:displayFinalMessage(). Fixes #1488 (#1490) --- automated install/basic-install.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index 5d893067..15fd93be 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -1129,10 +1129,18 @@ checkSelinux() { displayFinalMessage() { + if [[ ${#1} -gt 0 ]] ; then + pwstring="$1" + elif [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) -gt 0 ]]; then + pwstring="unchanged" + else + pwstring="NOT SET" + fi + if [[ ${INSTALL_WEB} == true ]]; then additional="View the web interface at http://pi.hole/admin or http://${IPV4_ADDRESS%/*}/admin -Your Admin Webpage login password is ${1:-"NOT SET"}" +Your Admin Webpage login password is ${pwstring}" fi # Final completion message to user From 085f2c6ca0f1f19649a523f14df6327b71adbb48 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Tue, 23 May 2017 22:32:30 -0500 Subject: [PATCH 037/162] add port check function --- advanced/Scripts/piholeDebug.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 634e2ffa..5215794e 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -326,12 +326,29 @@ ping_internet() { fi } +check_required_ports() { + echo -e " ${INFO} Ports in use:" + ports_in_use=() + while IFS= read -r line; do + ports_in_use+=( "$line" ) + done < <( lsof -i -P -n | awk -F' ' '/LISTEN/ {print $9, $1}' | sort | uniq | cut -d':' -f2 ) + + for i in ${!ports_in_use[@]}; do + local port_number="$(echo "${ports_in_use[$i]}" | awk '{print $1}')" + local service_name=$(echo "${ports_in_use[$i]}" | awk '{print $2}') + echo -e " [${port_number}] is in use by ${service_name}" + done +} + + check_networking() { echo_current_diagnostic "Networking" detect_ip_addresses "4" ping_gateway "4" detect_ip_addresses "6" ping_gateway "6" + port_check 4 http + check_required_ports } parse_file() { From 1a87d3a6592593cb58aaed8c7dd46a7af8c76d22 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Tue, 23 May 2017 22:57:22 -0500 Subject: [PATCH 038/162] add process check function --- advanced/Scripts/piholeDebug.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 5215794e..42d126d4 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -351,6 +351,16 @@ check_networking() { check_required_ports } +process_status(){ + echo_current_diagnostic "Pi-hole processes" + PROCESSES=( dnsmasq lighttpd pihole-FTL ) + local i + for i in "${PROCESSES[@]}"; do + local status_of_process=$(systemctl is-active "${i}") + echo -e " [i] ${i} daemon is ${status_of_process}" + done +} + parse_file() { # Set the first argument passed to tihs function as a named variable for better readability local filename="${1}" @@ -437,5 +447,6 @@ diagnose_setup_variables diagnose_operating_system processor_check check_networking +process_status check_critical_dependencies check_dnsmasq_d From 4ad0cdf5d40d1b5bc1517837b62682366237a783 Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Thu, 25 May 2017 01:03:13 +1000 Subject: [PATCH 039/162] Rewrite Chronometer to output more stats --- advanced/Scripts/chronometer.sh | 456 +++++++++++++++++++++++++++----- 1 file changed, 393 insertions(+), 63 deletions(-) diff --git a/advanced/Scripts/chronometer.sh b/advanced/Scripts/chronometer.sh index b5d54e5f..763091d8 100755 --- a/advanced/Scripts/chronometer.sh +++ b/advanced/Scripts/chronometer.sh @@ -8,98 +8,428 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. -# Functions -piLog="/var/log/pihole.log" -gravity="/etc/pihole/gravity.list" +# Retrieve stats from FTL engine +pihole-FTL() { + ftl_port=$(cat /var/run/pihole-FTL.port 2> /dev/null) + if [[ -n "$ftl_port" ]]; then + # Open connection to FTL + exec 3<>"/dev/tcp/localhost/$ftl_port" -. /etc/pihole/setupVars.conf + # Test if connection is open + if { "true" >&3; } 2> /dev/null; then + # Send command to FTL + echo -e ">$1" >&3 -function GetFTLData { - # Open connection to FTL - exec 3<>/dev/tcp/localhost/"$(cat /var/run/pihole-FTL.port)" + # Read input + read -r -t 1 LINE <&3 + until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do + echo "$LINE" >&1 + read -r -t 1 LINE <&3 + done - # Test if connection is open - if { >&3; } 2> /dev/null; then - # Send command to FTL - echo -e ">$1" >&3 - - # Read input - read -r -t 1 LINE <&3 - until [ ! $? ] || [[ "$LINE" == *"EOM"* ]]; do - echo "$LINE" >&1 - read -r -t 1 LINE <&3 - done - - # Close connection - exec 3>&- - exec 3<&- + # Close connection + exec 3>&- + exec 3<&- + fi + else + echo -e "${COL_LIGHT_RED}FTL offline${COL_NC}" fi } -outputJSON() { - get_summary_data - echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}" +# Print spaces to align right-side content +printFunc() { + txt_len="${#2}" + + # Reduce string length when using colour code + [ "${2:0:1}" == "" ] && txt_len=$((txt_len-7)) + + if [[ "$3" == "last" ]]; then + # Prevent final line from printing trailing newline + scr_size=( $(stty size 2>/dev/null || echo 24 80) ) + scr_width="${scr_size[1]}" + + title_len="${#1}" + spc_num=$(( (scr_width - title_len) - txt_len )) + [[ "$spc_num" -lt 0 ]] && spc_num="0" + spc=$(printf "%${spc_num}s") + + printf "%s%s$spc" "$1" "$2" + else + # Determine number of spaces for padding + spc_num=$(( 20 - txt_len )) + [[ "$spc_num" -lt 0 ]] && spc_num="0" + spc=$(printf "%${spc_num}s") + + # Print string (Max 20 characters, prevents overflow) + printf "%s%s$spc" "$1" "${2:0:20}" + fi } -get_summary_data() { - local summary=$(GetFTLData "stats") - domains_being_blocked_raw=$(grep "domains_being_blocked" <<< "${summary}" | grep -Eo "[0-9]+$") - domains_being_blocked=$(printf "%'.f" ${domains_being_blocked_raw}) - dns_queries_today_raw=$(grep "dns_queries_today" <<< "$summary" | grep -Eo "[0-9]+$") - dns_queries_today=$(printf "%'.f" ${dns_queries_today_raw}) - ads_blocked_today_raw=$(grep "ads_blocked_today" <<< "$summary" | grep -Eo "[0-9]+$") - ads_blocked_today=$(printf "%'.f" ${ads_blocked_today_raw}) - ads_percentage_today_raw=$(grep "ads_percentage_today" <<< "$summary" | grep -Eo "[0-9.]+$") - LC_NUMERIC=C ads_percentage_today=$(printf "%'.f" ${ads_percentage_today_raw}) +# Perform on first Chrono run (not for JSON formatted string) +get_init_stats() { + LC_NUMERIC=C + calcFunc(){ awk "BEGIN {print $*}"; } + + # Convert bytes to human-readable format + hrBytes() { + awk '{ + num=$1; + if(num==0) { + print "0 B" + } else { + xxx=(num<0?-num:num) + sss=(num<0?-1:1) + split("B KB MB GB TB PB",type) + for(i=5;yyy < 1;i--) { + yyy=xxx / (2^(10*i)) + } + printf "%.0f " type[i+2], yyy*sss + } + }' <<< "$1"; + } + + # Convert seconds to human-readable format + hrSecs() { + day=$(( $1/60/60/24 )); hrs=$(( $1/3600%24 )); mins=$(( ($1%3600)/60 )); secs=$(( $1%60 )) + [[ "$day" -ge "2" ]] && plu="s" + [[ "$day" -ge "1" ]] && days="$day day${plu}, " || days="" + printf "%s%02d:%02d:%02d\n" "$days" "$hrs" "$mins" "$secs" + } + + # Set Colour Codes + coltable="/opt/pihole/COL_TABLE" + if [[ -f "${coltable}" ]]; then + source ${coltable} + else + COL_NC='' + COL_DARK_GRAY='' + COL_LIGHT_GREEN='' + COL_LIGHT_BLUE='' + COL_LIGHT_RED='' + COL_YELLOW='' + COL_LIGHT_RED='' + COL_URG_RED='' + fi + + # Get RPi model number, or OS distro info + if command -v vcgencmd &> /dev/null; then + sys_rev=$(awk '/Revision/ {print $3}' < /proc/cpuinfo) + case "$sys_rev" in + 000[2-6]) sys_model=" 1, Model B";; # 256MB + 000[7-9]) sys_model=" 1, Model A" ;; # 256MB + 000d|000e|000f) sys_model=" 1, Model B";; # 512MB + 0010|0013) sys_model=" 1, Model B+";; # 512MB + 0012|0015) sys_model=" 1, Model A+";; # 256MB + a0104[0-1]|a21041|a22042) sys_model=" 2, Model B";; # 1GB + 900021) sys_model=" 1, Model A+";; # 512MB + 900032) sys_model=" 1, Model B+";; # 512MB + 90009[2-3]|920093) sys_model=" Zero";; # 512MB + 9000c1) sys_model=" Zero W";; # 512MB + a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB + *) sys_model="" ;; + esac + sys_type="Raspberry Pi$sys_model" + else + source "/etc/os-release" + CODENAME=$(sed 's/[()]//g' <<< "${VERSION/* /}") + sys_type="${NAME/ */} ${CODENAME^} $VERSION_ID" + fi + + # Get core count + sys_cores=$(grep -c "^processor" /proc/cpuinfo) + [[ "$sys_cores" -ne 1 ]] && sys_cores_plu="cores" || sys_cores_plu="core" + + # Test existence of clock speed file for ARM CPU + if [[ -f "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]]; then + scaling_freq_file="/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" + fi + + # Test existence of temperature file + if [[ -f "/sys/class/thermal/thermal_zone0/temp" ]]; then + temp_file="/sys/class/thermal/thermal_zone0/temp" + elif [[ -f "/sys/class/hwmon/hwmon0/temp1_input" ]]; then + temp_file="/sys/class/hwmon/hwmon0/temp1_input" + else + temp_file="" + fi + + # Test existence of setupVars config + if [[ -f "/etc/pihole/setupVars.conf" ]]; then + setupVars="/etc/pihole/setupVars.conf" + fi } -normalChrono() { +get_sys_stats() { + local ph_ver_raw + local cpu_raw + local ram_raw + local disk_raw + + # Update every 12 refreshes (Def: every 60s) + count=$((count+1)) + if [[ "$count" == "1" ]] || (( "$count" % 12 == 0 )); then + [[ -n "$setupVars" ]] && source "$setupVars" + + + ph_ver_raw=($(pihole -v -c 2> /dev/null | sed -n 's/^.* v/v/p')) + if [[ -n "${ph_ver_raw[0]}" ]]; then + ph_core_ver="${ph_ver_raw[0]}" + ph_lte_ver="${ph_ver_raw[1]}" + ph_ftl_ver="${ph_ver_raw[2]}" + else + ph_core_ver="${COL_LIGHT_RED}API unavailable${COL_NC}" + fi + + sys_name=$(hostname) + + [[ -n "$TEMPERATUREUNIT" ]] && temp_unit="$TEMPERATUREUNIT" || temp_unit="c" + + # Get storage stats for partition mounted on / + disk_raw=($(df -B1 / 2> /dev/null | awk 'END{ print $3,$2,$5 }')) + disk_used="${disk_raw[0]}" + disk_total="${disk_raw[1]}" + disk_perc="${disk_raw[2]}" + + net_gateway=$(route -n | awk '$4 == "UG" {print $2;exit}') + + # Get DHCP stats, if feature is enabled + if [[ "$DHCP_ACTIVE" == "true" ]]; then + ph_dhcp_eip="${DHCP_END##*.}" + ph_dhcp_max=$(( ${DHCP_END##*.} - ${DHCP_START##*.} + 1 )) + fi + + # Get alt DNS server, or print total count of alt DNS servers + if [[ -z "${PIHOLE_DNS_3}" ]]; then + ph_alts="${PIHOLE_DNS_2}" + else + dns_count="0" + [[ -n "${PIHOLE_DNS_2}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_3}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_4}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_5}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_6}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_7}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_8}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_9}" ]] && dns_count="$dns_count+" + ph_alts="${dns_count} others" + fi + fi + + sys_uptime=$(hrSecs "$(cut -d. -f1 /proc/uptime)") + sys_loadavg=$(cut -d " " -f1,2,3 /proc/loadavg) + + # Get CPU usage, only counting processes over 1% CPU as active + cpu_raw=$(ps -eo pcpu,rss --no-headers | grep -E -v " 0") + cpu_tasks=$(wc -l <<< "$cpu_raw") + cpu_taskact=$(sed -r "/(^ 0.)/d" <<< "$cpu_raw" | wc -l) + cpu_perc=$(awk '{sum+=$1} END {printf "%.0f\n", sum/'"$sys_cores"'}' <<< "$cpu_raw") + + # Get CPU clock speed + if [[ -n "$scaling_freq_file" ]]; then + cpu_mhz=$(( $(< /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 )) + else + cpu_mhz=$(lscpu | awk -F "[ .]+" '/MHz/ {print $4;exit}') + fi + + # Determine correct string format for CPU clock speed + if [[ -n "$cpu_mhz" ]]; then + [[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(calcFunc "$cpu_mhz"/1000) Ghz" + [[ -n "$cpu_freq" ]] && cpu_freq_str=" @ $cpu_freq" || cpu_freq_str="" + fi + + # Determine colour for temperature + if [[ -n "$temp_file" ]]; then + if [[ "$temp_unit" == "C" ]]; then + cpu_temp=$(printf "%'.0fc\n" "$(calcFunc "$(< $temp_file) / 1000")") + + case "${cpu_temp::-1}" in + -*|[0-9]|[1-3][0-9]) cpu_col="$COL_LIGHT_BLUE";; + 4[0-9]) cpu_col="";; + 5[0-9]) cpu_col="$COL_YELLOW";; + 6[0-9]) cpu_col="$COL_LIGHT_RED";; + *) cpu_col="$COL_URG_RED";; + esac + + # $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED + cpu_temp_str=", $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY" + + elif [[ "$temp_unit" == "F" ]]; then + cpu_temp=$(printf "%'.0ff\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")") + + case "${cpu_temp::-1}" in + -*|[0-9]|[0-9][0-9]) cpu_col="$COL_LIGHT_BLUE";; + 1[0-1][0-9]) cpu_col="";; + 1[2-3][0-9]) cpu_col="$COL_YELLOW";; + 1[4-5][0-9]) cpu_col="$COL_LIGHT_RED";; + *) cpu_col="$COL_URG_RED";; + esac + + cpu_temp_str=", $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY" + + else + cpu_temp_str=$(printf ", %'.0fk\n" "$(calcFunc "($(< $temp_file) / 1000) + 273.15")") + fi + else + cpu_temp_str="" + fi + + ram_raw=($(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.0f %.0f %.0f", (total-free-buffers-cached)*100/total, (total-free-buffers-cached)*1024, total*1024}' /proc/meminfo)) + ram_perc="${ram_raw[0]}" + ram_used="${ram_raw[1]}" + ram_total="${ram_raw[2]}" + + if [[ "$(pihole status web 2> /dev/null)" == "1" ]]; then + ph_status="${COL_LIGHT_GREEN}Active" + else + ph_status="${COL_LIGHT_RED}Inactive" + fi + + if [[ "$DHCP_ACTIVE" == "true" ]]; then + ph_dhcp_num=$(wc -l 2> /dev/null < "/etc/pihole/dhcp.leases") + fi +} + +get_ftl_stats() { + local stats_raw + + stats_raw=($(pihole-FTL "stats")) + domains_being_blocked_raw="${stats_raw[1]}" + dns_queries_today_raw="${stats_raw[3]}" + ads_blocked_today_raw="${stats_raw[5]}" + ads_percentage_today_raw="${stats_raw[7]}" + + # Only retrieve these stats when not called from jsonFunc + if [[ -z "$1" ]]; then + local recent_blocked_raw + local top_ad_raw + local top_domain_raw + local top_client_raw + + domains_being_blocked=$(printf "%'.0f\n" "${domains_being_blocked_raw}") + dns_queries_today=$(printf "%'.0f\n" "${dns_queries_today_raw}") + ads_blocked_today=$(printf "%'.0f\n" "${ads_blocked_today_raw}") + ads_percentage_today=$(printf "%'.0f\n" "${ads_percentage_today_raw}") + + recent_blocked_raw=$(pihole-FTL recentBlocked) + top_ad_raw=($(pihole-FTL "top-ads (1)")) + top_domain_raw=($(pihole-FTL "top-domains (1)")) + top_client_raw=($(pihole-FTL "top-clients (1)")) + + # Limit strings to 40 characters to prevent overflow + recent_blocked="${recent_blocked_raw:0:40}" + top_ad="${top_ad_raw[2]:0:40}" + top_domain="${top_domain_raw[2]:0:40}" + [[ "${top_client_raw[3]}" ]] && top_client="${top_client_raw[3]:0:40}" || top_client="${top_client_raw[2]:0:40}" + fi +} + +chronoFunc() { + get_init_stats + for (( ; ; )); do - get_summary_data - domain=$(GetFTLData recentBlocked) + get_sys_stats + get_ftl_stats + + # Do not print LTE/FTL strings if API is unavailable + ph_core_str=" ${COL_DARK_GRAY}Pi-hole: $ph_core_ver${COL_NC}" + if [[ -n "$ph_lte_ver" ]]; then + ph_lte_str=" ${COL_DARK_GRAY}AdminLTE: $ph_lte_ver${COL_NC}" + ph_ftl_str=" ${COL_DARK_GRAY}FTL: $ph_ftl_ver${COL_NC}" + fi + clear - # Displays a colorful Pi-hole logo - echo " ___ _ _ _" - echo "| _ (_)___| |_ ___| |___" - echo "| _/ |___| ' \/ _ \ / -_)" - echo "|_| |_| |_||_\___/_\___|" - echo "" - echo " ${IPV4_ADDRESS}" - echo "" - uptime | cut -d' ' -f11- - #uptime -p # Doesn't work on all versions of uptime - uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}' - echo "-------------------------------" - echo "Recently blocked:" - echo " $domain" + + echo -e "|¯¯¯(¯)__|¯|_ ___|¯|___$ph_core_str +| ¯_/¯|__| ' \/ _ \ / -_)$ph_lte_str +|_| |_| |_||_\___/_\___|$ph_ftl_str + ${COL_DARK_GRAY}——————————————————————————————————————————————————————————${COL_NC}" - echo "Blocking: ${domains_being_blocked}" - echo "Queries: ${dns_queries_today}" - echo "Pi-holed: ${ads_blocked_today} (${ads_percentage_today}%)" - - sleep 5 + printFunc " Hostname: " "$sys_name" + [ -n "$sys_type" ] && printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$sys_type" "$COL_NC" || printf "\n" + + printf "%s\n" " Uptime: $sys_uptime" + + printFunc " Task Load: " "$sys_loadavg" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Active: $cpu_taskact of $cpu_tasks tasks" "$COL_NC" + + printFunc " CPU usage: " "$cpu_perc%" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$sys_cores $sys_cores_plu$cpu_freq_str$cpu_temp_str" "$COL_NC" + + printFunc " RAM usage: " "$ram_perc%" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Used: $(hrBytes "$ram_used") of $(hrBytes "$ram_total")" "$COL_NC" + + printFunc " HDD usage: " "$disk_perc" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Used: $(hrBytes "$disk_used") of $(hrBytes "$disk_total")" "$COL_NC" + + printFunc " LAN addr: " "${IPV4_ADDRESS:0:-3}" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Gateway: $net_gateway" "$COL_NC" + + if [[ "$DHCP_ACTIVE" == "true" ]]; then + printFunc " DHCP: " "$DHCP_START to $ph_dhcp_eip" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Leased: $ph_dhcp_num of $ph_dhcp_max" "$COL_NC" + fi + + printFunc " Pi-hole: " "$ph_status" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Blocking: $domains_being_blocked sites" "$COL_NC" + + printFunc " Ads Today: " "$ads_percentage_today%" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$ads_blocked_today of $dns_queries_today queries" "$COL_NC" + + printFunc " Fwd DNS: " "$PIHOLE_DNS_1" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Alt DNS: $ph_alts" "$COL_NC" + + echo -e " ${COL_DARK_GRAY}——————————————————————————————————————————————————————————${COL_NC}" + echo " Recently blocked: $recent_blocked" + echo " Top Advertiser: $top_ad" + echo " Top Domain: $top_domain" + printFunc " Top Client: " "$top_client" "last" + + if [[ "$1" == "exit" ]]; then + exit 0 + else + if [[ -n "$1" ]]; then + sleep "${1}" + else + sleep 5 + fi + fi + done } -displayHelp() { - echo "Usage: pihole -c [options] +jsonFunc() { + get_ftl_stats "json" + echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}" +} + +helpFunc() { + if [[ "$1" == "?" ]]; then + echo "Unknown option. Please view 'pihole -c --help' for more information" + else + echo "Usage: pihole -c [options] Example: 'pihole -c -j' Calculates stats and displays to an LCD Options: -j, --json Output stats as JSON formatted string + -r, --refresh Set update frequency (in seconds) + -e, --exit Output stats and exit witout refreshing -h, --help Display this help text" + fi + exit 0 } if [[ $# = 0 ]]; then - normalChrono + chronoFunc fi for var in "$@"; do case "$var" in - "-j" | "--json" ) outputJSON;; - "-h" | "--help" ) displayHelp;; - * ) exit 1;; + "-j" | "--json" ) jsonFunc;; + "-h" | "--help" ) helpFunc;; + "-r" | "--refresh" ) chronoFunc "$2";; + "-e" | "--exit" ) chronoFunc "exit";; + * ) helpFunc "?";; esac done From 76266cf31b1b631a6646add520e6b712b76f2acd Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Wed, 24 May 2017 15:29:31 -0500 Subject: [PATCH 040/162] add resolver functions and check directory content functions --- advanced/Scripts/piholeDebug.sh | 93 ++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 6 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 42d126d4..8e805536 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -340,17 +340,63 @@ check_required_ports() { done } - check_networking() { echo_current_diagnostic "Networking" detect_ip_addresses "4" ping_gateway "4" detect_ip_addresses "6" ping_gateway "6" - port_check 4 http check_required_ports } +check_x_headers() { + curl -Is localhost | awk '/X-Pi-hole/' + curl -Is localhost/admin/ | awk '/X-Pi-hole/' +} + +dig_at() { + local protocol="${1}" + local IP="${2}" + echo_current_diagnostic "Domain name resolution (IPv${protocol}) using a random blocked domain" + local url + local local_dig + local pihole_dig + local remote_dig + + if [[ ${protocol} == "6" ]]; then + local local_address="::1" + local pihole_address="${IPV6_ADDRESS%/*}" + local remote_address="2001:4860:4860::8888" + local record_type="AAAA" + else + local local_address="127.0.0.1" + local pihole_address="${IPV4_ADDRESS%/*}" + local remote_address="8.8.8.8" + local record_type="A" + fi + + # Find a random blocked url that has not been whitelisted. + local random_url=$(shuf -n 1 "${GRAVITYFILE}" | awk -F ' ' '{ print $2 }') + + if local_dig=$(dig -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then + echo -e " ${TICK} ${random_url} is ${local_dig} via localhost (${local_address})" + else + echo -e " ${CROSS} Failed to resolve ${random_url} via localhot (${local_address})" + fi + + if pihole_dig=$(dig -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then + echo -e " ${TICK} ${random_url} is ${pihole_dig} via Pi-hole (${pihole_address})" + else + echo -e " ${CROSS} Failed to resolve ${random_url} via Pi-hole (${pihole_address})" + fi + + if remote_dig=$(dig -"${protocol}" "${random_url}" @${remote_address} +short "${record_type}"); then + echo -e " ${TICK} ${random_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" + else + echo -e " ${CROSS} Failed to resolve ${random_url} via a remote, public DNS server (${remote_address})" + fi +} + process_status(){ echo_current_diagnostic "Pi-hole processes" PROCESSES=( dnsmasq lighttpd pihole-FTL ) @@ -397,6 +443,15 @@ diagnose_setup_variables() { parse_file "${VARSFILE}" } +check_name_resolution() { + # Check name resoltion from localhost, Pi-hole's IP, and Google's name severs + dig_at 4 "${IPV4_ADDRESS%/*}" + # If IPv6 enabled, check resolution + if [[ "${IPV6_ADDRESS}" ]]; then + dig_at 6 "${IPV6_ADDRESS%/*}" + fi +} + # This function can check a directory exists # Pi-hole has files in several places, so we will reuse this function dir_check() { @@ -405,7 +460,7 @@ dir_check() { # Display the current test that is running echo_current_diagnostic "contents of ${directory}" # For each file in the directory, - for filename in "${directory}"*; do + for filename in "${directory}"; do # check if exists first; if it does, file_exists "${filename}" && \ # show a success message @@ -418,14 +473,13 @@ dir_check() { list_files_in_dir() { # Set the first argument passed to tihs function as a named variable for better readability local dir_to_parse="${1}" - # Set another local variable for better readability - local filename # Store the files found in an array files_found=( $(ls "${dir_to_parse}") ) # For each file in the arry, for each_file in "${files_found[@]}"; do # display the information with the ${INFO} icon - echo " ${INFO} ${each_file}" + # Also print the permissions and the user/group + echo -e " ${INFO} ${each_file} ( $(ls -ld ${dir_to_parse}/${each_file} | awk '{print $1, $3, $4}') )" done } @@ -439,6 +493,30 @@ check_dnsmasq_d() { list_files_in_dir "${directory}" } +check_cron_d() { + # Set a local variable for better readability + local directory=/etc/cron.d + # Check if the directory exists + dir_check "${directory}" + # if it does, list the files in it + list_files_in_dir "${directory}" +} + +check_http_directory() { + # Set a local variable for better readability + local directory=/var/www/html + # Check if the directory exists + dir_check "${directory}" + # if it does, list the files in it + list_files_in_dir "${directory}" +} + +upload_to_tricorder() { +echo tricorder +} + +upload_to_tricorder + initiate_debug check_core_version check_web_version @@ -447,6 +525,9 @@ diagnose_setup_variables diagnose_operating_system processor_check check_networking +check_name_resolution process_status check_critical_dependencies check_dnsmasq_d +check_http_directory +check_cron_d From 8bafd12f95eca26ad023728946f39271182e5067 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Wed, 24 May 2017 16:10:14 -0500 Subject: [PATCH 041/162] fix resolver functions and add x-header function --- advanced/Scripts/piholeDebug.sh | 35 ++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 8e805536..b275c4e5 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -350,8 +350,22 @@ check_networking() { } check_x_headers() { - curl -Is localhost | awk '/X-Pi-hole/' - curl -Is localhost/admin/ | awk '/X-Pi-hole/' + echo_current_diagnostic "Dashboard and block page" + local block_page=$(curl -Is localhost | awk '/X-Pi-hole/' | tr -d '\r') + local dashboard=$(curl -Is localhost/admin/ | awk '/X-Pi-hole/' | tr -d '\r') + local block_page_working="X-Pi-hole: A black hole for Internet advertisements.." + local dashboard_working="X-Pi-hole: The Pi-hole Web interface is working!!" + if [[ $block_page == $block_page_working ]]; then + echo -e " $TICK ${block_page}" + else + echo -e " $CROSS X-Header does not match or could not be retrieved" + fi + + if [[ $dashboard == $dashboard_working ]]; then + echo -e " $TICK ${dashboard}" + else + echo -e " $CROSS X-Header does not match or could not be retrieved" + fi } dig_at() { @@ -378,22 +392,24 @@ dig_at() { # Find a random blocked url that has not been whitelisted. local random_url=$(shuf -n 1 "${GRAVITYFILE}" | awk -F ' ' '{ print $2 }') + local remote_url="doubleclick.com" + if local_dig=$(dig -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then - echo -e " ${TICK} ${random_url} is ${local_dig} via localhost (${local_address})" + echo -e " ${TICK} ${random_url} is ${local_dig} via localhost (${local_address})" else - echo -e " ${CROSS} Failed to resolve ${random_url} via localhot (${local_address})" + echo -e " ${CROSS} Failed to resolve ${random_url} via localhot (${local_address})" fi if pihole_dig=$(dig -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then - echo -e " ${TICK} ${random_url} is ${pihole_dig} via Pi-hole (${pihole_address})" + echo -e " ${TICK} ${random_url} is ${pihole_dig} via Pi-hole (${pihole_address})" else - echo -e " ${CROSS} Failed to resolve ${random_url} via Pi-hole (${pihole_address})" + echo -e " ${CROSS} Failed to resolve ${random_url} via Pi-hole (${pihole_address})" fi - if remote_dig=$(dig -"${protocol}" "${random_url}" @${remote_address} +short "${record_type}"); then - echo -e " ${TICK} ${random_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" + if remote_dig=$(dig -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then + echo -e " ${TICK} ${random_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" else - echo -e " ${CROSS} Failed to resolve ${random_url} via a remote, public DNS server (${remote_address})" + echo -e " ${CROSS} Failed to resolve ${remote_url} via a remote, public DNS server (${remote_address})" fi } @@ -527,6 +543,7 @@ processor_check check_networking check_name_resolution process_status +check_x_headers check_critical_dependencies check_dnsmasq_d check_http_directory From 6684af9938e52137349674830a4339e1a9b02ab8 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Wed, 24 May 2017 18:31:55 -0500 Subject: [PATCH 042/162] add lighttpd list function and gravity analysis --- advanced/Scripts/piholeDebug.sh | 61 ++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index b275c4e5..1cff71c8 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -353,8 +353,8 @@ check_x_headers() { echo_current_diagnostic "Dashboard and block page" local block_page=$(curl -Is localhost | awk '/X-Pi-hole/' | tr -d '\r') local dashboard=$(curl -Is localhost/admin/ | awk '/X-Pi-hole/' | tr -d '\r') - local block_page_working="X-Pi-hole: A black hole for Internet advertisements.." - local dashboard_working="X-Pi-hole: The Pi-hole Web interface is working!!" + local block_page_working="X-Pi-hole: A black hole for Internet advertisements." + local dashboard_working="X-Pi-hole: The Pi-hole Web interface is working!" if [[ $block_page == $block_page_working ]]; then echo -e " $TICK ${block_page}" else @@ -509,6 +509,15 @@ check_dnsmasq_d() { list_files_in_dir "${directory}" } +check_lighttpd_d() { + # Set a local variable for better readability + local directory=/etc/lighttpd + # Check if the directory exists + dir_check "${directory}" + # if it does, list the files in it + list_files_in_dir "${directory}" +} + check_cron_d() { # Set a local variable for better readability local directory=/etc/cron.d @@ -527,11 +536,51 @@ check_http_directory() { list_files_in_dir "${directory}" } -upload_to_tricorder() { -echo tricorder +analyze_gravity_list() { + gravity_length=$(grep -c ^ "${GRAVITYFILE}") && \ + echo -e " ${INFO} ${GRAVITYFILE} is ${gravity_length} lines long." || \ + echo -e " ${CROSS} ${GRAVITYFILE} not found!" } -upload_to_tricorder +upload_to_tricorder() { + local tricorder + echo "${TICK} Finshed debugging!" + + # Ensure the file exists, create if not, clear if exists. + truncate --size=0 "${DEBUG_LOG}" + # Set the permissions and owner + chmod 644 ${DEBUG_LOG} + chown "$USER":pihole ${DEBUG_LOG} + # Copy working temp file to final log location + cat /proc/$$/fd/3 >> "${DEBUG_LOG}" + # Straight dump of tailing the logs, can sanitize later if needed. + cat /proc/$$/fd/4 >> "${DEBUG_LOG}" + + echo "::: The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." + if [[ "${AUTOMATED}" ]]; then + echo "${INFO} Debug script running in automated mode; uploading log to tricorder..." + tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999) + else + read -r -p "\n\n[?] 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 "${INFO} Log will NOT be uploaded to tricorder.";; + esac + fi + # Check if tricorder.pi-hole.net is reachable and provide token. + if [[ -n "${tricorder}" ]]; then + echo "::: ---=== Your debug token is : ${tricorder} Please make a note of it. ===---" + echo "::: Contact the Pi-hole team with your token for assistance." + echo "::: Thank you." + else + echo "::: There was an error uploading your debug log." + echo "::: Please try again or contact the Pi-hole team for assistance." + fi + echo "::: A local copy of the Debug log can be found at : /var/log/pihole_debug.log" + +} + + initiate_debug check_core_version @@ -546,5 +595,7 @@ process_status check_x_headers check_critical_dependencies check_dnsmasq_d +check_lighttpd_d check_http_directory check_cron_d +upload_to_tricorder From c995c81fff30731064c1a41c5a99ab9786b612a4 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Wed, 24 May 2017 19:36:06 -0500 Subject: [PATCH 043/162] adjust some spacing --- advanced/Scripts/piholeDebug.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 1cff71c8..75809b74 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -356,15 +356,15 @@ check_x_headers() { local block_page_working="X-Pi-hole: A black hole for Internet advertisements." local dashboard_working="X-Pi-hole: The Pi-hole Web interface is working!" if [[ $block_page == $block_page_working ]]; then - echo -e " $TICK ${block_page}" + echo -e " $TICK ${block_page}" else - echo -e " $CROSS X-Header does not match or could not be retrieved" + echo -e " $CROSS X-Header does not match or could not be retrieved" fi if [[ $dashboard == $dashboard_working ]]; then - echo -e " $TICK ${dashboard}" + echo -e " $TICK ${dashboard}" else - echo -e " $CROSS X-Header does not match or could not be retrieved" + echo -e " $CROSS X-Header does not match or could not be retrieved" fi } @@ -395,21 +395,21 @@ dig_at() { local remote_url="doubleclick.com" if local_dig=$(dig -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then - echo -e " ${TICK} ${random_url} is ${local_dig} via localhost (${local_address})" + echo -e " ${TICK} ${random_url} is ${local_dig} via localhost (${local_address})" else - echo -e " ${CROSS} Failed to resolve ${random_url} via localhot (${local_address})" + echo -e " ${CROSS} Failed to resolve ${random_url} via localhot (${local_address})" fi if pihole_dig=$(dig -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then - echo -e " ${TICK} ${random_url} is ${pihole_dig} via Pi-hole (${pihole_address})" + echo -e " ${TICK} ${random_url} is ${pihole_dig} via Pi-hole (${pihole_address})" else - echo -e " ${CROSS} Failed to resolve ${random_url} via Pi-hole (${pihole_address})" + echo -e " ${CROSS} Failed to resolve ${random_url} via Pi-hole (${pihole_address})" fi if remote_dig=$(dig -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then - echo -e " ${TICK} ${random_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" + echo -e " ${TICK} ${random_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" else - echo -e " ${CROSS} Failed to resolve ${remote_url} via a remote, public DNS server (${remote_address})" + echo -e " ${CROSS} Failed to resolve ${remote_url} via a remote, public DNS server (${remote_address})" fi } From 1102fdc44bc4ea1fa67b08b5c8137de674a8345d Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Wed, 24 May 2017 20:24:23 -0500 Subject: [PATCH 044/162] append everything the user sees to the pihole_debug.log file --- advanced/Scripts/piholeDebug.sh | 110 ++++++++++++++++---------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 75809b74..84074160 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -50,21 +50,21 @@ echo_succes_or_fail() { # Set the first argument passed to tihs function as a named variable for better readability local message="${1}" # If the command was successful (a zero), - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then # show success - echo -e " ${TICK} ${message}" + echo -e " ${TICK} ${message}" 2>&1 | tee -a "${DEBUG_LOG}" else # Otherwise, show a error - echo -e " ${CROSS} ${message}" + echo -e " ${CROSS} ${message}" 2>&1 | tee -a "${DEBUG_LOG}" fi } initiate_debug() { # Clear the screen so the debug log is readable clear - echo -e "${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC}" + echo -e "${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC}" 2>&1 | tee "${DEBUG_LOG}" # Timestamp the start of the log - echo -e " ${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initiated." + echo -e " ${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initiated." 2>&1 | tee -a "${DEBUG_LOG}" } # This is a function for visually displaying the curent test that is being run. @@ -72,7 +72,7 @@ initiate_debug() { # Colors do not show in the dasboard, but the icons do: [i], [✓], and [✗] echo_current_diagnostic() { # Colors are used for visually distinguishing each test in the output - echo -e "\n${COL_LIGHT_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}" + echo -e "\n${COL_LIGHT_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}" 2>&1 | tee -a "${DEBUG_LOG}" } file_exists() { @@ -106,16 +106,16 @@ check_core_version() { local error_msg="git status failed" if_directory_exists "${PIHOLEGITDIR}" && \ cd "${PIHOLEGITDIR}" || \ - echo "pihole repo does not exist" + echo -e "pihole repo does not exist" 2>&1 | tee -a "${DEBUG_LOG}" if git status &> /dev/null; then PI_HOLE_VERSION=$(git describe --tags --abbrev=0); PI_HOLE_BRANCH=$(git rev-parse --abbrev-ref HEAD); PI_HOLE_COMMIT=$(git describe --long --dirty --tags --always) echo -e " ${INFO} Core: ${PI_HOLE_VERSION} ${INFO} Branch: ${PI_HOLE_BRANCH} - ${INFO} Commit: ${PI_HOLE_COMMIT}" + ${INFO} Commit: ${PI_HOLE_COMMIT}" 2>&1 | tee -a "${DEBUG_LOG}" else - echo "${error_msg}" + echo -e "${error_msg}" 2>&1 | tee -a "${DEBUG_LOG}" return 1 fi } @@ -124,54 +124,54 @@ check_web_version() { local error_msg="git status failed" if_directory_exists "${ADMINGITDIR}" && \ cd "${ADMINGITDIR}" || \ - echo "repo does not exist" + echo -e "repo does not exist" 2>&1 | tee -a "${DEBUG_LOG}" if git status &> /dev/null; then WEB_VERSION=$(git describe --tags --abbrev=0); WEB_BRANCH=$(git rev-parse --abbrev-ref HEAD); WEB_COMMIT=$(git describe --long --dirty --tags --always) echo -e " ${INFO} Web: ${WEB_VERSION} ${INFO} Branch: ${WEB_BRANCH} - ${INFO} Commit: ${WEB_COMMIT}" + ${INFO} Commit: ${WEB_COMMIT}" 2>&1 | tee -a "${DEBUG_LOG}" else - echo "${error_msg}" + echo -e "${error_msg}" 2>&1 | tee -a "${DEBUG_LOG}" return 1 fi } check_ftl_version() { FTL_VERSION=$(pihole-FTL version) - echo -e " ${INFO} FTL: ${FTL_VERSION}" + echo -e " ${INFO} FTL: ${FTL_VERSION}" 2>&1 | tee -a "${DEBUG_LOG}" } check_web_server_version() { WEB_SERVER="lighttpd" WEB_SERVER_VERSON="$(lighttpd -v |& head -n1 | cut -d '/' -f2 | cut -d ' ' -f1)" - echo -e " ${INFO} ${WEB_SERVER}" + echo -e " ${INFO} ${WEB_SERVER}" 2>&1 | tee -a "${DEBUG_LOG}" if [[ -z "${WEB_SERVER_VERSON}" ]]; then - echo -e " ${CROSS} ${WEB_SERVER} version could not be detected." + echo -e " ${CROSS} ${WEB_SERVER} version could not be detected." 2>&1 | tee -a "${DEBUG_LOG}" else - echo -e " ${TICK} ${WEB_SERVER_VERSON}" + echo -e " ${TICK} ${WEB_SERVER_VERSON}" 2>&1 | tee -a "${DEBUG_LOG}" fi } check_resolver_version() { RESOLVER="dnsmasq" RESOVLER_VERSON="$(dnsmasq -v |& head -n1 | awk '{print $3}')" - echo -e " ${INFO} ${RESOLVER}" + echo -e " ${INFO} ${RESOLVER}" 2>&1 | tee -a "${DEBUG_LOG}" if [[ -z "${RESOVLER_VERSON}" ]]; then - echo -e " ${CROSS} ${RESOLVER} version could not be detected." + echo -e " ${CROSS} ${RESOLVER} version could not be detected." 2>&1 | tee -a "${DEBUG_LOG}" else - echo -e " ${TICK} ${RESOVLER_VERSON}" + echo -e " ${TICK} ${RESOVLER_VERSON}" 2>&1 | tee -a "${DEBUG_LOG}" fi } check_php_version() { PHP_VERSION=$(php -v |& head -n1 | cut -d '-' -f1 | cut -d ' ' -f2) - echo -e " ${INFO} PHP" + echo -e " ${INFO} PHP" 2>&1 | tee -a "${DEBUG_LOG}" if [[ -z "${PHP_VERSION}" ]]; then - echo -e " ${CROSS} PHP version could not be detected." + echo -e " ${CROSS} PHP version could not be detected." 2>&1 | tee -a "${DEBUG_LOG}" else - echo -e " ${TICK} ${PHP_VERSION}" + echo -e " ${TICK} ${PHP_VERSION}" 2>&1 | tee -a "${DEBUG_LOG}" fi } @@ -199,7 +199,7 @@ get_distro_attributes() { # we need just the OS PRETTY_NAME, so print it when we find it if [[ "${pretty_name_key}" == "PRETTY_NAME" ]]; then PRETTY_NAME=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f2- | tr -d '"') - echo " ${INFO} ${PRETTY_NAME}" + echo -e " ${INFO} ${PRETTY_NAME}" 2>&1 | tee -a "${DEBUG_LOG}" # Otherwise, do nothing else : @@ -221,16 +221,16 @@ diagnose_operating_system() { get_distro_attributes || \ # If it doesn't exist, it's not a system we currently support and link to FAQ echo -e " ${CROSS} ${COL_LIGHT_RED}${error_msg}${COL_NC} - ${INFO} ${COL_LIGHT_RED}Please see${COL_NC}: ${COL_CYAN}${faq_url}${COL_NC}" + ${INFO} ${COL_LIGHT_RED}Please see${COL_NC}: ${COL_CYAN}${faq_url}${COL_NC}" 2>&1 | tee -a "${DEBUG_LOG}" } processor_check() { echo_current_diagnostic "Processor" PROCESSOR=$(uname -m) if [[ -z "${PROCESSOR}" ]]; then - echo -e " ${CROSS} Processor could not be identified." + echo -e " ${CROSS} Processor could not be identified." 2>&1 | tee -a "${DEBUG_LOG}" else - echo -e " ${INFO} ${PROCESSOR}" + echo -e " ${INFO} ${PROCESSOR}" 2>&1 | tee -a "${DEBUG_LOG}" fi } @@ -246,13 +246,13 @@ detect_ip_addresses() { if [[ -n ${ip_addr_list} ]]; then # Local iterator local i - echo -e " ${TICK} IPv${protocol} on ${PIHOLE_INTERFACE}" + echo -e " ${TICK} IPv${protocol} on ${PIHOLE_INTERFACE}" 2>&1 | tee -a "${DEBUG_LOG}" for i in "${!ip_addr_list[@]}"; do - echo -e " [$i] ${ip_addr_list[$i]}" + echo -e " [$i] ${ip_addr_list[$i]}" 2>&1 | tee -a "${DEBUG_LOG}" done # Othwerwise explain that the protocol is not configured else - echo -e " ${CROSS} No IPv${protocol} found on ${PIHOLE_INTERFACE}" + echo -e " ${CROSS} No IPv${protocol} found on ${PIHOLE_INTERFACE}" 2>&1 | tee -a "${DEBUG_LOG}" return 1 fi } @@ -282,19 +282,19 @@ ping_gateway() { # If the gateway variable has a value (meaning a gateway was found), if [[ -n "${gateway}" ]]; then # Let the user know we will ping the gateway for a response - echo -e " ${INFO} Trying three pings on IPv${protocol} gateway at ${gateway}..." + echo -e " ${INFO} Trying three pings on IPv${protocol} gateway at ${gateway}..." 2>&1 | tee -a "${DEBUG_LOG}" # Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only, # on the pihole interface, and tail the last three lines of the output # If pinging the gateway is not successful, if ! ping_cmd="$(${cmd} -q -c 3 -W 3 -n ${gateway} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then # let the user know - echo -e " ${CROSS} Gateway did not respond." + echo -e " ${CROSS} Gateway did not respond." 2>&1 | tee -a "${DEBUG_LOG}" # and return an error code return 1 # Otherwise, else # show a success - echo -e " ${TICK} Gateway responded." + echo -e " ${TICK} Gateway responded." 2>&1 | tee -a "${DEBUG_LOG}" # and return a success code return 0 fi @@ -316,18 +316,18 @@ ping_internet() { # and Google's public IPv4 address local public_address="8.8.8.8" fi - echo -n " ${INFO} Trying three pings on IPv${protocol} to reach the Internet..." + echo -n " ${INFO} Trying three pings on IPv${protocol} to reach the Internet..." 2>&1 | tee -a "${DEBUG_LOG}" if ! ping_inet="$(${cmd} -q -W 3 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then - echo -e " ${CROSS} Cannot reach the Internet" + echo -e " ${CROSS} Cannot reach the Internet" 2>&1 | tee -a "${DEBUG_LOG}" return 1 else - echo -e " ${TICK} Query responded." + echo -e " ${TICK} Query responded." 2>&1 | tee -a "${DEBUG_LOG}" return 0 fi } check_required_ports() { - echo -e " ${INFO} Ports in use:" + echo -e " ${INFO} Ports in use:" 2>&1 | tee -a "${DEBUG_LOG}" ports_in_use=() while IFS= read -r line; do ports_in_use+=( "$line" ) @@ -336,7 +336,7 @@ check_required_ports() { for i in ${!ports_in_use[@]}; do local port_number="$(echo "${ports_in_use[$i]}" | awk '{print $1}')" local service_name=$(echo "${ports_in_use[$i]}" | awk '{print $2}') - echo -e " [${port_number}] is in use by ${service_name}" + echo -e " [${port_number}] is in use by ${service_name}" 2>&1 | tee -a "${DEBUG_LOG}" done } @@ -356,15 +356,15 @@ check_x_headers() { local block_page_working="X-Pi-hole: A black hole for Internet advertisements." local dashboard_working="X-Pi-hole: The Pi-hole Web interface is working!" if [[ $block_page == $block_page_working ]]; then - echo -e " $TICK ${block_page}" + echo -e " $TICK ${block_page}" 2>&1 | tee -a "${DEBUG_LOG}" else - echo -e " $CROSS X-Header does not match or could not be retrieved" + echo -e " $CROSS X-Header does not match or could not be retrieved" 2>&1 | tee -a "${DEBUG_LOG}" fi if [[ $dashboard == $dashboard_working ]]; then - echo -e " $TICK ${dashboard}" + echo -e " $TICK ${dashboard}" 2>&1 | tee -a "${DEBUG_LOG}" else - echo -e " $CROSS X-Header does not match or could not be retrieved" + echo -e " $CROSS X-Header does not match or could not be retrieved" 2>&1 | tee -a "${DEBUG_LOG}" fi } @@ -395,21 +395,21 @@ dig_at() { local remote_url="doubleclick.com" if local_dig=$(dig -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then - echo -e " ${TICK} ${random_url} is ${local_dig} via localhost (${local_address})" + echo -e " ${TICK} ${random_url} is ${local_dig} via localhost (${local_address})" 2>&1 | tee -a "${DEBUG_LOG}" else - echo -e " ${CROSS} Failed to resolve ${random_url} via localhot (${local_address})" + echo -e " ${CROSS} Failed to resolve ${random_url} via localhot (${local_address})" 2>&1 | tee -a "${DEBUG_LOG}" fi if pihole_dig=$(dig -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then - echo -e " ${TICK} ${random_url} is ${pihole_dig} via Pi-hole (${pihole_address})" + echo -e " ${TICK} ${random_url} is ${pihole_dig} via Pi-hole (${pihole_address})" 2>&1 | tee -a "${DEBUG_LOG}" else - echo -e " ${CROSS} Failed to resolve ${random_url} via Pi-hole (${pihole_address})" + echo -e " ${CROSS} Failed to resolve ${random_url} via Pi-hole (${pihole_address})" 2>&1 | tee -a "${DEBUG_LOG}" fi if remote_dig=$(dig -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then - echo -e " ${TICK} ${random_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" + echo -e " ${TICK} ${random_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" 2>&1 | tee -a "${DEBUG_LOG}" else - echo -e " ${CROSS} Failed to resolve ${remote_url} via a remote, public DNS server (${remote_address})" + echo -e " ${CROSS} Failed to resolve ${remote_url} via a remote, public DNS server (${remote_address})" 2>&1 | tee -a "${DEBUG_LOG}" fi } @@ -419,7 +419,7 @@ process_status(){ local i for i in "${PROCESSES[@]}"; do local status_of_process=$(systemctl is-active "${i}") - echo -e " [i] ${i} daemon is ${status_of_process}" + echo -e " [i] ${i} daemon is ${status_of_process}" 2>&1 | tee -a "${DEBUG_LOG}" done } @@ -436,7 +436,7 @@ parse_file() { # For each lin in the file, for file_lines in "${file_info[@]}"; do # display the information with the ${INFO} icon - echo " ${INFO} ${file_lines}" + echo -e " ${INFO} ${file_lines}" 2>&1 | tee -a "${DEBUG_LOG}" done # Set the IFS back to what it was IFS="$OLD_IFS" @@ -450,7 +450,7 @@ diagnose_setup_variables() { file_exists "${VARSFILE}" && \ # source it source ${VARSFILE}; - echo -e " ${INFO} Sourcing ${VARSFILE}..."; + echo -e " ${INFO} Sourcing ${VARSFILE}..." 2>&1 | tee -a "${DEBUG_LOG}"; # and display a green check mark with ${DONE} echo_succes_or_fail "${VARSFILE} is readable and has been sourced." || \ # Othwerwise, error out @@ -495,7 +495,7 @@ list_files_in_dir() { for each_file in "${files_found[@]}"; do # display the information with the ${INFO} icon # Also print the permissions and the user/group - echo -e " ${INFO} ${each_file} ( $(ls -ld ${dir_to_parse}/${each_file} | awk '{print $1, $3, $4}') )" + echo -e " ${INFO} ${each_file} ( $(ls -ld ${dir_to_parse}/${each_file} | awk '{print $1, $3, $4}') )" 2>&1 | tee -a "${DEBUG_LOG}" done } @@ -538,13 +538,13 @@ check_http_directory() { analyze_gravity_list() { gravity_length=$(grep -c ^ "${GRAVITYFILE}") && \ - echo -e " ${INFO} ${GRAVITYFILE} is ${gravity_length} lines long." || \ - echo -e " ${CROSS} ${GRAVITYFILE} not found!" + echo -e " ${INFO} ${GRAVITYFILE} is ${gravity_length} lines long." 2>&1 | tee -a "${DEBUG_LOG}" || \ + echo -e " ${CROSS} ${GRAVITYFILE} not found!" 2>&1 | tee -a "${DEBUG_LOG}" } upload_to_tricorder() { local tricorder - echo "${TICK} Finshed debugging!" + echo -e "${TICK} Finshed debugging!" 2>&1 | tee -a "${DEBUG_LOG}" # Ensure the file exists, create if not, clear if exists. truncate --size=0 "${DEBUG_LOG}" @@ -598,4 +598,4 @@ check_dnsmasq_d check_lighttpd_d check_http_directory check_cron_d -upload_to_tricorder +#upload_to_tricorder From cc946ce068b7b153ad4d3761b161f400e21c0b2d Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Wed, 24 May 2017 21:11:15 -0500 Subject: [PATCH 045/162] upload to tricorder functions --- advanced/Scripts/piholeDebug.sh | 67 +++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 84074160..d484354a 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -542,46 +542,63 @@ analyze_gravity_list() { echo -e " ${CROSS} ${GRAVITYFILE} not found!" 2>&1 | tee -a "${DEBUG_LOG}" } -upload_to_tricorder() { - local tricorder - echo -e "${TICK} Finshed debugging!" 2>&1 | tee -a "${DEBUG_LOG}" +tricorder_nc_or_ssl() { + if command -v openssl &> /dev/null; then + echo -e " ${INFO} Using openssl for transmission." 2>&1 | tee -a "${DEBUG_LOG}" + tricorder=$(cat /var/log/pihole_debug.log | openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null) + else + echo -e " ${INFO} Using netcat for transmission." 2>&1 | tee -a "${DEBUG_LOG}" + tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999) + fi +} - # Ensure the file exists, create if not, clear if exists. - truncate --size=0 "${DEBUG_LOG}" + +upload_to_tricorder() { # Set the permissions and owner chmod 644 ${DEBUG_LOG} chown "$USER":pihole ${DEBUG_LOG} - # Copy working temp file to final log location - cat /proc/$$/fd/3 >> "${DEBUG_LOG}" - # Straight dump of tailing the logs, can sanitize later if needed. - cat /proc/$$/fd/4 >> "${DEBUG_LOG}" - echo "::: The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." + echo "" + echo -e "${TICK} Finshed debugging!" 2>&1 | tee -a "${DEBUG_LOG}" + + echo -e " ${INFO} The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." + echo -e " For more information, see: https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/" if [[ "${AUTOMATED}" ]]; then - echo "${INFO} Debug script running in automated mode; uploading log to tricorder..." - tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999) + echo -e " ${INFO} Debug script running in automated mode" 2>&1 | tee -a "${DEBUG_LOG}" + if command -v openssl &> /dev/null; then + echo -e " ${INFO} Using openssl for transmission." 2>&1 | tee -a "${DEBUG_LOG}" + openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin + else + echo -e " ${INFO} Using netcat for transmission." 2>&1 | tee -a "${DEBUG_LOG}" + nc tricorder.pi-hole.net 9999 < /dev/stdin + fi else - read -r -p "\n\n[?] Would you like to upload the log? [y/N] " response + echo "" + 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 "${INFO} Log will NOT be uploaded to tricorder.";; + [yY][eE][sS]|[yY]) tricorder_nc_or_ssl;; + *) echo -e " ${INFO} Log will NOT be uploaded to tricorder.";exit; esac fi # Check if tricorder.pi-hole.net is reachable and provide token. if [[ -n "${tricorder}" ]]; then - echo "::: ---=== Your debug token is : ${tricorder} Please make a note of it. ===---" - echo "::: Contact the Pi-hole team with your token for assistance." - echo "::: Thank you." + echo "" + echo -e "${COL_LIGHT_PURPLE}***********************************${COL_NC}" + echo -e "${TICK} Your debug token is: ${COL_LIGHT_GREEN}${tricorder}${COL_NC}" + echo -e "${COL_LIGHT_PURPLE}***********************************${COL_NC}" + echo -e "" + echo -e " Provide this token to the Pi-hole team for assistance:" + echo "" + echo -e " https://discourse.pi-hole.net" else - echo "::: There was an error uploading your debug log." - echo "::: Please try again or contact the Pi-hole team for assistance." + echo -e " ${CROSS} There was an error uploading your debug log." + echo -e " Please try again or contact the Pi-hole team for assistance." fi - echo "::: A local copy of the Debug log can be found at : /var/log/pihole_debug.log" - + echo "" + echo -e " A local copy of the debug log can be found at : /var/log/pihole_debug.log" + echo "" } - - initiate_debug check_core_version check_web_version @@ -598,4 +615,4 @@ check_dnsmasq_d check_lighttpd_d check_http_directory check_cron_d -#upload_to_tricorder +upload_to_tricorder From 5902be2a49214f614b29c114c810dda4d3c047f9 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Wed, 24 May 2017 22:07:15 -0500 Subject: [PATCH 046/162] comments for every line --- advanced/Scripts/piholeDebug.sh | 145 ++++++++++++++++++++++++++++++-- 1 file changed, 138 insertions(+), 7 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index d484354a..5e280e62 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -32,6 +32,7 @@ WHITELISTMATCHES="/tmp/whitelistmatches.list" readonly FTLLOG="/var/log/pihole-FTL.log" coltable=/opt/pihole/COL_TABLE +# These provide the colors we need for making the log more readable if [[ -f ${coltable} ]]; then source ${coltable} else @@ -47,7 +48,7 @@ else fi echo_succes_or_fail() { - # Set the first argument passed to tihs function as a named variable for better readability + # Set the first argument passed to this function as a named variable for better readability local message="${1}" # If the command was successful (a zero), if [[ $? -eq 0 ]]; then @@ -102,80 +103,133 @@ if_directory_exists() { } check_core_version() { + # Checks the core version of the Pi-hole codebase echo_current_diagnostic "Pi-hole Versions" + # Store the error message in a variable in case we want to change and/or reuse it local error_msg="git status failed" + # If the pihole git directory exists, if_directory_exists "${PIHOLEGITDIR}" && \ + # move into it cd "${PIHOLEGITDIR}" || \ + # if not, report an error echo -e "pihole repo does not exist" 2>&1 | tee -a "${DEBUG_LOG}" + # If the git status command completes successfully, + # we can assume we can get the information we want if git status &> /dev/null; then + # The current version the user is on PI_HOLE_VERSION=$(git describe --tags --abbrev=0); + # What branch they are on PI_HOLE_BRANCH=$(git rev-parse --abbrev-ref HEAD); + # The commit they are on PI_HOLE_COMMIT=$(git describe --long --dirty --tags --always) + # echo this information out to the user in a nice format echo -e " ${INFO} Core: ${PI_HOLE_VERSION} ${INFO} Branch: ${PI_HOLE_BRANCH} ${INFO} Commit: ${PI_HOLE_COMMIT}" 2>&1 | tee -a "${DEBUG_LOG}" + # If git status failed, else + # Return an error message echo -e "${error_msg}" 2>&1 | tee -a "${DEBUG_LOG}" + # and exit with a non zero code return 1 fi } check_web_version() { + # Local variable for the error message local error_msg="git status failed" + # If the directory exists, if_directory_exists "${ADMINGITDIR}" && \ + # move into it cd "${ADMINGITDIR}" || \ + # if not, give an error message echo -e "repo does not exist" 2>&1 | tee -a "${DEBUG_LOG}" + # If the git status command completes successfully, + # we can assume we can get the information we want if git status &> /dev/null; then + # The current version the user is on WEB_VERSION=$(git describe --tags --abbrev=0); + # What branch they are on WEB_BRANCH=$(git rev-parse --abbrev-ref HEAD); + # The commit they are on WEB_COMMIT=$(git describe --long --dirty --tags --always) + # echo this information out to the user in a nice format echo -e " ${INFO} Web: ${WEB_VERSION} ${INFO} Branch: ${WEB_BRANCH} ${INFO} Commit: ${WEB_COMMIT}" 2>&1 | tee -a "${DEBUG_LOG}" + # If git status failed, else + # Return an error message echo -e "${error_msg}" 2>&1 | tee -a "${DEBUG_LOG}" + # and exit with a non zero code return 1 fi } check_ftl_version() { + # Use the built in command to check FTL's version FTL_VERSION=$(pihole-FTL version) + # and display it to the user echo -e " ${INFO} FTL: ${FTL_VERSION}" 2>&1 | tee -a "${DEBUG_LOG}" } +# Check the current version of the Web server check_web_server_version() { + # Store the name in a variable in case we ever want to change it WEB_SERVER="lighttpd" + # Parse out just the version number WEB_SERVER_VERSON="$(lighttpd -v |& head -n1 | cut -d '/' -f2 | cut -d ' ' -f1)" + # Display the information to the user echo -e " ${INFO} ${WEB_SERVER}" 2>&1 | tee -a "${DEBUG_LOG}" + # If the Web server does not have a version (the variable is empty) if [[ -z "${WEB_SERVER_VERSON}" ]]; then + # Display and error echo -e " ${CROSS} ${WEB_SERVER} version could not be detected." 2>&1 | tee -a "${DEBUG_LOG}" + # Otherwise, else + # display the version echo -e " ${TICK} ${WEB_SERVER_VERSON}" 2>&1 | tee -a "${DEBUG_LOG}" fi } +# Check the current version of the DNS server check_resolver_version() { + # Store the name in a variable in case we ever want to change it RESOLVER="dnsmasq" + # Parse out just the version number RESOVLER_VERSON="$(dnsmasq -v |& head -n1 | awk '{print $3}')" + # Display the information to the user echo -e " ${INFO} ${RESOLVER}" 2>&1 | tee -a "${DEBUG_LOG}" + # If the DNS server does not have a version (the variable is empty) if [[ -z "${RESOVLER_VERSON}" ]]; then + # Display and error echo -e " ${CROSS} ${RESOLVER} version could not be detected." 2>&1 | tee -a "${DEBUG_LOG}" + # Otherwise, else + # display the version echo -e " ${TICK} ${RESOVLER_VERSON}" 2>&1 | tee -a "${DEBUG_LOG}" fi } check_php_version() { + # Parse out just the version number PHP_VERSION=$(php -v |& head -n1 | cut -d '-' -f1 | cut -d ' ' -f2) + # Display the info to the user echo -e " ${INFO} PHP" 2>&1 | tee -a "${DEBUG_LOG}" + # If no version is detected, if [[ -z "${PHP_VERSION}" ]]; then + # show an error echo -e " ${CROSS} PHP version could not be detected." 2>&1 | tee -a "${DEBUG_LOG}" + # otherwise, else + # Show the version echo -e " ${TICK} ${PHP_VERSION}" 2>&1 | tee -a "${DEBUG_LOG}" fi } +# These are the most critical dependencies of Pi-hole, so we check for them +# and their versions, using the functions above. check_critical_dependencies() { echo_current_diagnostic "Versions of critical dependencies" check_web_server_version @@ -210,14 +264,16 @@ get_distro_attributes() { } diagnose_operating_system() { + # local variable for system requirements local faq_url="https://discourse.pi-hole.net/t/hardware-software-requirements/273" + # error message in a variable so we can easily modify it later (or re-use it) local error_msg="Distribution unknown -- most likely you are on an unsupported platform and may run into issues." # Display the current test that is running echo_current_diagnostic "Operating system" # If there is a /etc/*release file, it's probably a supported operating system, so we can file_exists /etc/*release && \ - # display the attributes to the user + # display the attributes to the user from the function made earlier get_distro_attributes || \ # If it doesn't exist, it's not a system we currently support and link to FAQ echo -e " ${CROSS} ${COL_LIGHT_RED}${error_msg}${COL_NC} @@ -226,10 +282,15 @@ diagnose_operating_system() { processor_check() { echo_current_diagnostic "Processor" + # Store the processor type in a variable PROCESSOR=$(uname -m) + # If it does not contain a value, if [[ -z "${PROCESSOR}" ]]; then + # we couldn't detect it, so show an error echo -e " ${CROSS} Processor could not be identified." 2>&1 | tee -a "${DEBUG_LOG}" + # Otherwise, else + # Show the processor type echo -e " ${INFO} ${PROCESSOR}" 2>&1 | tee -a "${DEBUG_LOG}" fi } @@ -246,12 +307,16 @@ detect_ip_addresses() { if [[ -n ${ip_addr_list} ]]; then # Local iterator local i + # Display the protocol and interface echo -e " ${TICK} IPv${protocol} on ${PIHOLE_INTERFACE}" 2>&1 | tee -a "${DEBUG_LOG}" + # Since there may be more than one IP address, store them in an array for i in "${!ip_addr_list[@]}"; do + # For each one in the list, print it out using the iterator as a numbered list echo -e " [$i] ${ip_addr_list[$i]}" 2>&1 | tee -a "${DEBUG_LOG}" done - # Othwerwise explain that the protocol is not configured + # Othwerwise, else + # explain that the protocol is not configured echo -e " ${CROSS} No IPv${protocol} found on ${PIHOLE_INTERFACE}" 2>&1 | tee -a "${DEBUG_LOG}" return 1 fi @@ -302,6 +367,7 @@ ping_gateway() { } ping_internet() { + # Give the first argument a readable name local protocol="${1}" # If the protocol is 6, if [[ ${protocol} == "6" ]]; then @@ -317,30 +383,42 @@ ping_internet() { local public_address="8.8.8.8" fi echo -n " ${INFO} Trying three pings on IPv${protocol} to reach the Internet..." 2>&1 | tee -a "${DEBUG_LOG}" + # Try to ping the address 3 times if ! ping_inet="$(${cmd} -q -W 3 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then + # if it's unsuccessful, show an error echo -e " ${CROSS} Cannot reach the Internet" 2>&1 | tee -a "${DEBUG_LOG}" return 1 + # Otherwise, else + # show success echo -e " ${TICK} Query responded." 2>&1 | tee -a "${DEBUG_LOG}" return 0 fi } check_required_ports() { + # Since Pi-hole needs 53, 80, and 4711, check what they are being used by + # so we can detect any issues echo -e " ${INFO} Ports in use:" 2>&1 | tee -a "${DEBUG_LOG}" + # Create an array for these ports in use ports_in_use=() + # Sort the addresses and remove duplicates while IFS= read -r line; do ports_in_use+=( "$line" ) done < <( lsof -i -P -n | awk -F' ' '/LISTEN/ {print $9, $1}' | sort | uniq | cut -d':' -f2 ) + # Now that we have the values stored, for i in ${!ports_in_use[@]}; do local port_number="$(echo "${ports_in_use[$i]}" | awk '{print $1}')" local service_name=$(echo "${ports_in_use[$i]}" | awk '{print $2}') + # display the information nicely to the user echo -e " [${port_number}] is in use by ${service_name}" 2>&1 | tee -a "${DEBUG_LOG}" done } check_networking() { + # Runs through several of the functions made earlier; we just clump them + # together since they are all related to the networking aspect of things echo_current_diagnostic "Networking" detect_ip_addresses "4" ping_gateway "4" @@ -350,17 +428,27 @@ check_networking() { } check_x_headers() { + # The X-Headers allow us to determine from the command line if the Web + # server is operating correctly echo_current_diagnostic "Dashboard and block page" + # Use curl -I to get the header and parse out just the X-Pi-hole one local block_page=$(curl -Is localhost | awk '/X-Pi-hole/' | tr -d '\r') + # Do it for the dashboard as well, as the header is different than above local dashboard=$(curl -Is localhost/admin/ | awk '/X-Pi-hole/' | tr -d '\r') + # Store what the X-Header shoud be in variables for comparision later local block_page_working="X-Pi-hole: A black hole for Internet advertisements." local dashboard_working="X-Pi-hole: The Pi-hole Web interface is working!" + # If the X-header found by curl matches what is should be, if [[ $block_page == $block_page_working ]]; then + # display a success message echo -e " $TICK ${block_page}" 2>&1 | tee -a "${DEBUG_LOG}" + # Otherwise, else + # show an error echo -e " $CROSS X-Header does not match or could not be retrieved" 2>&1 | tee -a "${DEBUG_LOG}" fi + # Same logic applies to the dashbord as above if [[ $dashboard == $dashboard_working ]]; then echo -e " $TICK ${dashboard}" 2>&1 | tee -a "${DEBUG_LOG}" else @@ -369,20 +457,29 @@ check_x_headers() { } dig_at() { + # We need to test if Pi-hole can properly resolve domain names as it is an + # essential piece of the software that needs to work + + # Store the arguments as variables with names local protocol="${1}" local IP="${2}" echo_current_diagnostic "Domain name resolution (IPv${protocol}) using a random blocked domain" + # Set more local variables local url local local_dig local pihole_dig local remote_dig + # If the protocol (4 or 6) is 6, if [[ ${protocol} == "6" ]]; then + # Set the IPv6 variables and record type local local_address="::1" local pihole_address="${IPV6_ADDRESS%/*}" local remote_address="2001:4860:4860::8888" local record_type="AAAA" + # Othwerwise, it should be 4 else + # so use the IPv4 values local local_address="127.0.0.1" local pihole_address="${IPV4_ADDRESS%/*}" local remote_address="8.8.8.8" @@ -392,33 +489,45 @@ dig_at() { # Find a random blocked url that has not been whitelisted. local random_url=$(shuf -n 1 "${GRAVITYFILE}" | awk -F ' ' '{ print $2 }') - local remote_url="doubleclick.com" - + # First do a dig on localhost, to see if Pi-hole can use itself to block a domain if local_dig=$(dig -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then + # If it can, show sucess echo -e " ${TICK} ${random_url} is ${local_dig} via localhost (${local_address})" 2>&1 | tee -a "${DEBUG_LOG}" + # Otherwise, else + # show a failure echo -e " ${CROSS} Failed to resolve ${random_url} via localhot (${local_address})" 2>&1 | tee -a "${DEBUG_LOG}" fi + # Next we need to check if Pi-hole can resolve a domain when the query is sent to it's IP address + # This better emulates how clients will interact with Pi-hole as opposed to above where Pi-hole is + # just asing itself locally if pihole_dig=$(dig -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then echo -e " ${TICK} ${random_url} is ${pihole_dig} via Pi-hole (${pihole_address})" 2>&1 | tee -a "${DEBUG_LOG}" else echo -e " ${CROSS} Failed to resolve ${random_url} via Pi-hole (${pihole_address})" 2>&1 | tee -a "${DEBUG_LOG}" fi + # Finally, we need to make sure legitimate sites can out if using an external, public DNS server if remote_dig=$(dig -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then + # If successful, the real IP of the domain will be returned instead of Pi-hole's IP echo -e " ${TICK} ${random_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" 2>&1 | tee -a "${DEBUG_LOG}" else - echo -e " ${CROSS} Failed to resolve ${remote_url} via a remote, public DNS server (${remote_address})" 2>&1 | tee -a "${DEBUG_LOG}" + echo -e " ${CROSS} Failed to resolve ${random_url} via a remote, public DNS server (${remote_address})" 2>&1 | tee -a "${DEBUG_LOG}" fi } process_status(){ + # Check to make sure Pi-hole's services are running and active echo_current_diagnostic "Pi-hole processes" + # Store them in an array for easy use PROCESSES=( dnsmasq lighttpd pihole-FTL ) local i + # For each process, for i in "${PROCESSES[@]}"; do + # get it's status local status_of_process=$(systemctl is-active "${i}") + # and print it out to the user echo -e " [i] ${i} daemon is ${status_of_process}" 2>&1 | tee -a "${DEBUG_LOG}" done } @@ -461,6 +570,7 @@ diagnose_setup_variables() { check_name_resolution() { # Check name resoltion from localhost, Pi-hole's IP, and Google's name severs + # using the function we created earlier dig_at 4 "${IPV4_ADDRESS%/*}" # If IPv6 enabled, check resolution if [[ "${IPV6_ADDRESS}" ]]; then @@ -537,16 +647,24 @@ check_http_directory() { } analyze_gravity_list() { + # It's helpful to know how big a user's gravity file is gravity_length=$(grep -c ^ "${GRAVITYFILE}") && \ echo -e " ${INFO} ${GRAVITYFILE} is ${gravity_length} lines long." 2>&1 | tee -a "${DEBUG_LOG}" || \ + # If the previous command failed, something is wrong with the file echo -e " ${CROSS} ${GRAVITYFILE} not found!" 2>&1 | tee -a "${DEBUG_LOG}" } tricorder_nc_or_ssl() { + # Users can submit their debug logs using nc (unencrypted) or opensll (enrypted) if available + # Check fist for openssl since encryption is a good thing if command -v openssl &> /dev/null; then + # If successful echo -e " ${INFO} Using openssl for transmission." 2>&1 | tee -a "${DEBUG_LOG}" + # transmit the log and store the token returned in the tricorder variable tricorder=$(cat /var/log/pihole_debug.log | openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null) + # Otherwise, else + # use net cat echo -e " ${INFO} Using netcat for transmission." 2>&1 | tee -a "${DEBUG_LOG}" tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999) fi @@ -558,13 +676,18 @@ upload_to_tricorder() { chmod 644 ${DEBUG_LOG} chown "$USER":pihole ${DEBUG_LOG} + # Let the user know debugging is complete echo "" echo -e "${TICK} Finshed debugging!" 2>&1 | tee -a "${DEBUG_LOG}" + # Provide information on what they should do with their token echo -e " ${INFO} The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." echo -e " For more information, see: https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/" + # If pihole -d is running automatically (usually throught the dashboard) if [[ "${AUTOMATED}" ]]; then + # let the user know echo -e " ${INFO} Debug script running in automated mode" 2>&1 | tee -a "${DEBUG_LOG}" + # and then decide again which tool to use to submit it if command -v openssl &> /dev/null; then echo -e " ${INFO} Using openssl for transmission." 2>&1 | tee -a "${DEBUG_LOG}" openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin @@ -574,13 +697,18 @@ upload_to_tricorder() { fi else echo "" + # Give the user a choice of uploading it or not + # Users can review the log file locally and try to self-diagnose their problem read -r -p "[?] Would you like to upload the log? [y/N] " response case ${response} in + # If they say yes, run our function for uploading the log [yY][eE][sS]|[yY]) tricorder_nc_or_ssl;; + # If they choose no, just exit out of the script *) echo -e " ${INFO} Log will NOT be uploaded to tricorder.";exit; esac fi - # Check if tricorder.pi-hole.net is reachable and provide token. + # Check if tricorder.pi-hole.net is reachable and provide token + # along with some additional useful information if [[ -n "${tricorder}" ]]; then echo "" echo -e "${COL_LIGHT_PURPLE}***********************************${COL_NC}" @@ -599,10 +727,13 @@ upload_to_tricorder() { echo "" } +# Run through all the functions we made initiate_debug check_core_version check_web_version check_ftl_version +# setupVars.conf needs to be sourced before the networking so the values are +# available to the check_networking function diagnose_setup_variables diagnose_operating_system processor_check From 10139241f5168e53015dd8e238f44289882c76e3 Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Fri, 26 May 2017 17:57:27 +1000 Subject: [PATCH 047/162] Fix output IPv4 addr when removing CIDR notation (#1498) --- advanced/Scripts/chronometer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced/Scripts/chronometer.sh b/advanced/Scripts/chronometer.sh index 763091d8..d9b7d05b 100755 --- a/advanced/Scripts/chronometer.sh +++ b/advanced/Scripts/chronometer.sh @@ -361,7 +361,7 @@ chronoFunc() { printFunc " HDD usage: " "$disk_perc" printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Used: $(hrBytes "$disk_used") of $(hrBytes "$disk_total")" "$COL_NC" - printFunc " LAN addr: " "${IPV4_ADDRESS:0:-3}" + printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}" printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Gateway: $net_gateway" "$COL_NC" if [[ "$DHCP_ACTIVE" == "true" ]]; then From 96f01e670fa13f0d5c77a7d305285d3b750d1668 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Fri, 26 May 2017 12:16:22 -0500 Subject: [PATCH 048/162] add functions to write to console and log at the same time --- advanced/Scripts/piholeDebug.sh | 177 ++++++++++++++++++-------------- 1 file changed, 101 insertions(+), 76 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 5e280e62..a9efcbbc 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -9,10 +9,14 @@ # Please see LICENSE file for your rights under this license. -# causes a pipeline to produce a failure return code if any command errors. -# Normally, pipelines only return a failure if the last command errors. -# In combination with set -e, this will make your script exit if any command in a pipeline errors. +# -e option instructs bash to immediately exit if any command [1] has a non-zero exit status +# -u a reference to any variable you haven't previously defined +# with the exceptions of $* and $@ - is an error, and causes the program to immediately exit +# -o pipefail prevents errors in a pipeline from being masked. If any command in a pipeline fails, +# that return code will be used as the return code of the whole pipeline. By default, the +# pipeline's return code is that of the last command - even if it succeeds set -o pipefail +IFS=$'\n\t' ######## GLOBAL VARS ######## VARSFILE="/etc/pihole/setupVars.conf" @@ -47,25 +51,44 @@ else OVER="\r\033[K" fi +make_temporary_log() { + # Create temporary file for log + TEMPLOG=$(mktemp /tmp/pihole_temp.XXXXXX) + # Open handle 3 for templog + # https://stackoverflow.com/questions/18460186/writing-outputs-to-log-file-and-console + exec 3>"$TEMPLOG" + # Delete templog, but allow for addressing via file handle. + rm "$TEMPLOG" +} + +log_write() { + # echo arguments to both the log and the console" + echo -e "${@}" | tee -a /proc/$$/fd/3 +} + +copy_to_debug_log() { + cat /proc/$$/fd/3 >> "${DEBUG_LOG}" +} + echo_succes_or_fail() { # Set the first argument passed to this function as a named variable for better readability local message="${1}" # If the command was successful (a zero), if [[ $? -eq 0 ]]; then # show success - echo -e " ${TICK} ${message}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${TICK} ${message}" else # Otherwise, show a error - echo -e " ${CROSS} ${message}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} ${message}" fi } initiate_debug() { # Clear the screen so the debug log is readable clear - echo -e "${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC}" 2>&1 | tee "${DEBUG_LOG}" + log_write "${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC}" 2>&1 | tee "${DEBUG_LOG}" # Timestamp the start of the log - echo -e " ${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initiated." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initiated." } # This is a function for visually displaying the curent test that is being run. @@ -73,7 +96,7 @@ initiate_debug() { # Colors do not show in the dasboard, but the icons do: [i], [✓], and [✗] echo_current_diagnostic() { # Colors are used for visually distinguishing each test in the output - echo -e "\n${COL_LIGHT_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write "\n${COL_LIGHT_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}" } file_exists() { @@ -112,7 +135,7 @@ check_core_version() { # move into it cd "${PIHOLEGITDIR}" || \ # if not, report an error - echo -e "pihole repo does not exist" 2>&1 | tee -a "${DEBUG_LOG}" + log_write "pihole repo does not exist" # If the git status command completes successfully, # we can assume we can get the information we want if git status &> /dev/null; then @@ -123,13 +146,13 @@ check_core_version() { # The commit they are on PI_HOLE_COMMIT=$(git describe --long --dirty --tags --always) # echo this information out to the user in a nice format - echo -e " ${INFO} Core: ${PI_HOLE_VERSION} + log_write " ${INFO} Core: ${PI_HOLE_VERSION} ${INFO} Branch: ${PI_HOLE_BRANCH} - ${INFO} Commit: ${PI_HOLE_COMMIT}" 2>&1 | tee -a "${DEBUG_LOG}" + ${INFO} Commit: ${PI_HOLE_COMMIT}" # If git status failed, else # Return an error message - echo -e "${error_msg}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write "${error_msg}" # and exit with a non zero code return 1 fi @@ -143,7 +166,7 @@ check_web_version() { # move into it cd "${ADMINGITDIR}" || \ # if not, give an error message - echo -e "repo does not exist" 2>&1 | tee -a "${DEBUG_LOG}" + log_write "repo does not exist" # If the git status command completes successfully, # we can assume we can get the information we want if git status &> /dev/null; then @@ -154,13 +177,13 @@ check_web_version() { # The commit they are on WEB_COMMIT=$(git describe --long --dirty --tags --always) # echo this information out to the user in a nice format - echo -e " ${INFO} Web: ${WEB_VERSION} + log_write " ${INFO} Web: ${WEB_VERSION} ${INFO} Branch: ${WEB_BRANCH} - ${INFO} Commit: ${WEB_COMMIT}" 2>&1 | tee -a "${DEBUG_LOG}" + ${INFO} Commit: ${WEB_COMMIT}" # If git status failed, else # Return an error message - echo -e "${error_msg}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write "${error_msg}" # and exit with a non zero code return 1 fi @@ -170,7 +193,7 @@ check_ftl_version() { # Use the built in command to check FTL's version FTL_VERSION=$(pihole-FTL version) # and display it to the user - echo -e " ${INFO} FTL: ${FTL_VERSION}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} FTL: ${FTL_VERSION}" } # Check the current version of the Web server @@ -180,15 +203,15 @@ check_web_server_version() { # Parse out just the version number WEB_SERVER_VERSON="$(lighttpd -v |& head -n1 | cut -d '/' -f2 | cut -d ' ' -f1)" # Display the information to the user - echo -e " ${INFO} ${WEB_SERVER}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} ${WEB_SERVER}" # If the Web server does not have a version (the variable is empty) if [[ -z "${WEB_SERVER_VERSON}" ]]; then # Display and error - echo -e " ${CROSS} ${WEB_SERVER} version could not be detected." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} ${WEB_SERVER} version could not be detected." # Otherwise, else # display the version - echo -e " ${TICK} ${WEB_SERVER_VERSON}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${TICK} ${WEB_SERVER_VERSON}" fi } @@ -199,15 +222,15 @@ check_resolver_version() { # Parse out just the version number RESOVLER_VERSON="$(dnsmasq -v |& head -n1 | awk '{print $3}')" # Display the information to the user - echo -e " ${INFO} ${RESOLVER}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} ${RESOLVER}" # If the DNS server does not have a version (the variable is empty) if [[ -z "${RESOVLER_VERSON}" ]]; then # Display and error - echo -e " ${CROSS} ${RESOLVER} version could not be detected." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} ${RESOLVER} version could not be detected." # Otherwise, else # display the version - echo -e " ${TICK} ${RESOVLER_VERSON}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${TICK} ${RESOVLER_VERSON}" fi } @@ -215,15 +238,15 @@ check_php_version() { # Parse out just the version number PHP_VERSION=$(php -v |& head -n1 | cut -d '-' -f1 | cut -d ' ' -f2) # Display the info to the user - echo -e " ${INFO} PHP" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} PHP" # If no version is detected, if [[ -z "${PHP_VERSION}" ]]; then # show an error - echo -e " ${CROSS} PHP version could not be detected." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} PHP version could not be detected." # otherwise, else # Show the version - echo -e " ${TICK} ${PHP_VERSION}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${TICK} ${PHP_VERSION}" fi } @@ -253,7 +276,7 @@ get_distro_attributes() { # we need just the OS PRETTY_NAME, so print it when we find it if [[ "${pretty_name_key}" == "PRETTY_NAME" ]]; then PRETTY_NAME=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f2- | tr -d '"') - echo -e " ${INFO} ${PRETTY_NAME}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} ${PRETTY_NAME}" # Otherwise, do nothing else : @@ -276,8 +299,8 @@ diagnose_operating_system() { # display the attributes to the user from the function made earlier get_distro_attributes || \ # If it doesn't exist, it's not a system we currently support and link to FAQ - echo -e " ${CROSS} ${COL_LIGHT_RED}${error_msg}${COL_NC} - ${INFO} ${COL_LIGHT_RED}Please see${COL_NC}: ${COL_CYAN}${faq_url}${COL_NC}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} ${COL_LIGHT_RED}${error_msg}${COL_NC} + ${INFO} ${COL_LIGHT_RED}Please see${COL_NC}: ${COL_CYAN}${faq_url}${COL_NC}" } processor_check() { @@ -287,11 +310,11 @@ processor_check() { # If it does not contain a value, if [[ -z "${PROCESSOR}" ]]; then # we couldn't detect it, so show an error - echo -e " ${CROSS} Processor could not be identified." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} Processor could not be identified." # Otherwise, else # Show the processor type - echo -e " ${INFO} ${PROCESSOR}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} ${PROCESSOR}" fi } @@ -308,16 +331,16 @@ detect_ip_addresses() { # Local iterator local i # Display the protocol and interface - echo -e " ${TICK} IPv${protocol} on ${PIHOLE_INTERFACE}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${TICK} IPv${protocol} on ${PIHOLE_INTERFACE}" # Since there may be more than one IP address, store them in an array for i in "${!ip_addr_list[@]}"; do # For each one in the list, print it out using the iterator as a numbered list - echo -e " [$i] ${ip_addr_list[$i]}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " [$i] ${ip_addr_list[$i]}" done # Othwerwise, else # explain that the protocol is not configured - echo -e " ${CROSS} No IPv${protocol} found on ${PIHOLE_INTERFACE}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} No IPv${protocol} found on ${PIHOLE_INTERFACE}" return 1 fi } @@ -347,19 +370,19 @@ ping_gateway() { # If the gateway variable has a value (meaning a gateway was found), if [[ -n "${gateway}" ]]; then # Let the user know we will ping the gateway for a response - echo -e " ${INFO} Trying three pings on IPv${protocol} gateway at ${gateway}..." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} Trying three pings on IPv${protocol} gateway at ${gateway}..." # Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only, # on the pihole interface, and tail the last three lines of the output # If pinging the gateway is not successful, if ! ping_cmd="$(${cmd} -q -c 3 -W 3 -n ${gateway} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then # let the user know - echo -e " ${CROSS} Gateway did not respond." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} Gateway did not respond." # and return an error code return 1 # Otherwise, else # show a success - echo -e " ${TICK} Gateway responded." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${TICK} Gateway responded." # and return a success code return 0 fi @@ -382,16 +405,16 @@ ping_internet() { # and Google's public IPv4 address local public_address="8.8.8.8" fi - echo -n " ${INFO} Trying three pings on IPv${protocol} to reach the Internet..." 2>&1 | tee -a "${DEBUG_LOG}" + echo -n " ${INFO} Trying three pings on IPv${protocol} to reach the Internet..." # Try to ping the address 3 times if ! ping_inet="$(${cmd} -q -W 3 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then # if it's unsuccessful, show an error - echo -e " ${CROSS} Cannot reach the Internet" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} Cannot reach the Internet" return 1 # Otherwise, else # show success - echo -e " ${TICK} Query responded." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${TICK} Query responded." return 0 fi } @@ -399,7 +422,7 @@ ping_internet() { check_required_ports() { # Since Pi-hole needs 53, 80, and 4711, check what they are being used by # so we can detect any issues - echo -e " ${INFO} Ports in use:" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} Ports in use:" # Create an array for these ports in use ports_in_use=() # Sort the addresses and remove duplicates @@ -412,7 +435,7 @@ check_required_ports() { local port_number="$(echo "${ports_in_use[$i]}" | awk '{print $1}')" local service_name=$(echo "${ports_in_use[$i]}" | awk '{print $2}') # display the information nicely to the user - echo -e " [${port_number}] is in use by ${service_name}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " [${port_number}] is in use by ${service_name}" done } @@ -441,18 +464,18 @@ check_x_headers() { # If the X-header found by curl matches what is should be, if [[ $block_page == $block_page_working ]]; then # display a success message - echo -e " $TICK ${block_page}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " $TICK ${block_page}" # Otherwise, else # show an error - echo -e " $CROSS X-Header does not match or could not be retrieved" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " $CROSS X-Header does not match or could not be retrieved" fi # Same logic applies to the dashbord as above if [[ $dashboard == $dashboard_working ]]; then - echo -e " $TICK ${dashboard}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " $TICK ${dashboard}" else - echo -e " $CROSS X-Header does not match or could not be retrieved" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " $CROSS X-Header does not match or could not be retrieved" fi } @@ -492,28 +515,28 @@ dig_at() { # First do a dig on localhost, to see if Pi-hole can use itself to block a domain if local_dig=$(dig -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then # If it can, show sucess - echo -e " ${TICK} ${random_url} is ${local_dig} via localhost (${local_address})" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${TICK} ${random_url} is ${local_dig} via localhost (${local_address})" # Otherwise, else # show a failure - echo -e " ${CROSS} Failed to resolve ${random_url} via localhot (${local_address})" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} Failed to resolve ${random_url} via localhot (${local_address})" fi # Next we need to check if Pi-hole can resolve a domain when the query is sent to it's IP address # This better emulates how clients will interact with Pi-hole as opposed to above where Pi-hole is # just asing itself locally if pihole_dig=$(dig -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then - echo -e " ${TICK} ${random_url} is ${pihole_dig} via Pi-hole (${pihole_address})" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${TICK} ${random_url} is ${pihole_dig} via Pi-hole (${pihole_address})" else - echo -e " ${CROSS} Failed to resolve ${random_url} via Pi-hole (${pihole_address})" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} Failed to resolve ${random_url} via Pi-hole (${pihole_address})" fi # Finally, we need to make sure legitimate sites can out if using an external, public DNS server if remote_dig=$(dig -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then # If successful, the real IP of the domain will be returned instead of Pi-hole's IP - echo -e " ${TICK} ${random_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${TICK} ${random_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" else - echo -e " ${CROSS} Failed to resolve ${random_url} via a remote, public DNS server (${remote_address})" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} Failed to resolve ${random_url} via a remote, public DNS server (${remote_address})" fi } @@ -528,7 +551,7 @@ process_status(){ # get it's status local status_of_process=$(systemctl is-active "${i}") # and print it out to the user - echo -e " [i] ${i} daemon is ${status_of_process}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " [i] ${i} daemon is ${status_of_process}" done } @@ -545,7 +568,7 @@ parse_file() { # For each lin in the file, for file_lines in "${file_info[@]}"; do # display the information with the ${INFO} icon - echo -e " ${INFO} ${file_lines}" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} ${file_lines}" done # Set the IFS back to what it was IFS="$OLD_IFS" @@ -559,7 +582,7 @@ diagnose_setup_variables() { file_exists "${VARSFILE}" && \ # source it source ${VARSFILE}; - echo -e " ${INFO} Sourcing ${VARSFILE}..." 2>&1 | tee -a "${DEBUG_LOG}"; + log_write " ${INFO} Sourcing ${VARSFILE}..."; # and display a green check mark with ${DONE} echo_succes_or_fail "${VARSFILE} is readable and has been sourced." || \ # Othwerwise, error out @@ -605,7 +628,7 @@ list_files_in_dir() { for each_file in "${files_found[@]}"; do # display the information with the ${INFO} icon # Also print the permissions and the user/group - echo -e " ${INFO} ${each_file} ( $(ls -ld ${dir_to_parse}/${each_file} | awk '{print $1, $3, $4}') )" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} ${each_file} ( $(ls -ld ${dir_to_parse}/${each_file} | awk '{print $1, $3, $4}') )" done } @@ -649,9 +672,9 @@ check_http_directory() { analyze_gravity_list() { # It's helpful to know how big a user's gravity file is gravity_length=$(grep -c ^ "${GRAVITYFILE}") && \ - echo -e " ${INFO} ${GRAVITYFILE} is ${gravity_length} lines long." 2>&1 | tee -a "${DEBUG_LOG}" || \ + log_write " ${INFO} ${GRAVITYFILE} is ${gravity_length} lines long." || \ # If the previous command failed, something is wrong with the file - echo -e " ${CROSS} ${GRAVITYFILE} not found!" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${CROSS} ${GRAVITYFILE} not found!" } tricorder_nc_or_ssl() { @@ -659,13 +682,13 @@ tricorder_nc_or_ssl() { # Check fist for openssl since encryption is a good thing if command -v openssl &> /dev/null; then # If successful - echo -e " ${INFO} Using openssl for transmission." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} Using openssl for transmission." # transmit the log and store the token returned in the tricorder variable tricorder=$(cat /var/log/pihole_debug.log | openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null) # Otherwise, else # use net cat - echo -e " ${INFO} Using netcat for transmission." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} Using netcat for transmission." tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999) fi } @@ -678,21 +701,21 @@ upload_to_tricorder() { # Let the user know debugging is complete echo "" - echo -e "${TICK} Finshed debugging!" 2>&1 | tee -a "${DEBUG_LOG}" + log_write "${TICK} Finshed debugging!" # Provide information on what they should do with their token - echo -e " ${INFO} The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." - echo -e " For more information, see: https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/" + log_write " ${INFO} The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." + log_write " For more information, see: https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/" # If pihole -d is running automatically (usually throught the dashboard) if [[ "${AUTOMATED}" ]]; then # let the user know - echo -e " ${INFO} Debug script running in automated mode" 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} Debug script running in automated mode" # and then decide again which tool to use to submit it if command -v openssl &> /dev/null; then - echo -e " ${INFO} Using openssl for transmission." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} Using openssl for transmission." openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin else - echo -e " ${INFO} Using netcat for transmission." 2>&1 | tee -a "${DEBUG_LOG}" + log_write " ${INFO} Using netcat for transmission." nc tricorder.pi-hole.net 9999 < /dev/stdin fi else @@ -704,30 +727,31 @@ upload_to_tricorder() { # If they say yes, run our function for uploading the log [yY][eE][sS]|[yY]) tricorder_nc_or_ssl;; # If they choose no, just exit out of the script - *) echo -e " ${INFO} Log will NOT be uploaded to tricorder.";exit; + *) log_write " ${INFO} Log will NOT be uploaded to tricorder.";exit; esac fi # Check if tricorder.pi-hole.net is reachable and provide token # along with some additional useful information if [[ -n "${tricorder}" ]]; then echo "" - echo -e "${COL_LIGHT_PURPLE}***********************************${COL_NC}" - echo -e "${TICK} Your debug token is: ${COL_LIGHT_GREEN}${tricorder}${COL_NC}" - echo -e "${COL_LIGHT_PURPLE}***********************************${COL_NC}" - echo -e "" - echo -e " Provide this token to the Pi-hole team for assistance:" + log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" + log_write "${TICK} Your debug token is: ${COL_LIGHT_GREEN}${tricorder}${COL_NC}" + log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" + log_write "" + log_write " Provide this token to the Pi-hole team for assistance:" echo "" - echo -e " https://discourse.pi-hole.net" + log_write " https://discourse.pi-hole.net" else - echo -e " ${CROSS} There was an error uploading your debug log." - echo -e " Please try again or contact the Pi-hole team for assistance." + log_write " ${CROSS} There was an error uploading your debug log." + log_write " Please try again or contact the Pi-hole team for assistance." fi echo "" - echo -e " A local copy of the debug log can be found at : /var/log/pihole_debug.log" + log_write " A local copy of the debug log can be found at : /var/log/pihole_debug.log" echo "" } # Run through all the functions we made +make_temporary_log initiate_debug check_core_version check_web_version @@ -746,4 +770,5 @@ check_dnsmasq_d check_lighttpd_d check_http_directory check_cron_d +copy_to_debug_log upload_to_tricorder From ef5a6e7880901ed0c6d9aef4cf658f12fa04aa2c Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Fri, 26 May 2017 14:26:02 -0500 Subject: [PATCH 049/162] add faq urls to some functions, added more colors, also use a static url for remote digs --- advanced/Scripts/piholeDebug.sh | 103 +++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 22 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index a9efcbbc..5691b6af 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -16,7 +16,7 @@ # that return code will be used as the return code of the whole pipeline. By default, the # pipeline's return code is that of the last command - even if it succeeds set -o pipefail -IFS=$'\n\t' +#IFS=$'\n\t' ######## GLOBAL VARS ######## VARSFILE="/etc/pihole/setupVars.conf" @@ -67,6 +67,7 @@ log_write() { } copy_to_debug_log() { + # Copy the contents of file descriptor 3 into the debug log so it can be uploaded to tricorder cat /proc/$$/fd/3 >> "${DEBUG_LOG}" } @@ -146,9 +147,21 @@ check_core_version() { # The commit they are on PI_HOLE_COMMIT=$(git describe --long --dirty --tags --always) # echo this information out to the user in a nice format - log_write " ${INFO} Core: ${PI_HOLE_VERSION} - ${INFO} Branch: ${PI_HOLE_BRANCH} - ${INFO} Commit: ${PI_HOLE_COMMIT}" + # If the current version matches what pihole -v produces, the user is up-to-date + if [[ "${PI_HOLE_VERSION}" == "$(pihole -v | awk '/Pi-hole/ {print $6}' | cut -d ')' -f1)" ]]; then + log_write " ${TICK} Core: ${COL_LIGHT_GREEN}${PI_HOLE_VERSION}${COL_NC}" + # If not, + else + # pring the current version in yellow + log_write " ${INFO} Core: ${COL_YELLOW}${PI_HOLE_VERSION:-Untagged}${COL_NC} (See ${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC} on how to update Pi-hole)" + fi + + if [[ "${PI_HOLE_BRANCH}" == "master" ]]; then + log_write " ${INFO} Branch: ${COL_LIGHT_GREEN}${PI_HOLE_BRANCH}${COL_NC}" + else + log_write " ${INFO} Branch: ${COL_YELLOW}${PI_HOLE_BRANCH:-Detached}${COL_NC} (See ${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC} for more information)" + fi + log_write " ${INFO} Commit: ${PI_HOLE_COMMIT}" # If git status failed, else # Return an error message @@ -177,9 +190,18 @@ check_web_version() { # The commit they are on WEB_COMMIT=$(git describe --long --dirty --tags --always) # echo this information out to the user in a nice format - log_write " ${INFO} Web: ${WEB_VERSION} - ${INFO} Branch: ${WEB_BRANCH} - ${INFO} Commit: ${WEB_COMMIT}" + if [[ "${WEB_VERSION}" == "$(pihole -v | awk '/AdminLTE/ {print $6}' | cut -d ')' -f1)" ]]; then + log_write " ${TICK} Web: ${COL_LIGHT_GREEN}${WEB_VERSION}${COL_NC}" + else + log_write " ${INFO} Web: ${COL_YELLOW}${WEB_VERSION:-Untagged}${COL_NC} (See ${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC} on how to update Pi-hole)" + fi + + if [[ "${WEB_BRANCH}" == "master" ]]; then + log_write " ${TICK} Branch: ${COL_LIGHT_GREEN}${WEB_BRANCH}${COL_NC}" + else + log_write " ${INFO} Branch: ${COL_YELLOW}${WEB_BRANCH:-Detached}${COL_NC} (See ${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC} for more information)" + fi + log_write " ${INFO} Commit: ${WEB_COMMIT}" # If git status failed, else # Return an error message @@ -216,7 +238,7 @@ check_web_server_version() { } # Check the current version of the DNS server -check_resolver_version() { +check_resolver_server_version() { # Store the name in a variable in case we ever want to change it RESOLVER="dnsmasq" # Parse out just the version number @@ -256,7 +278,7 @@ check_php_version() { check_critical_dependencies() { echo_current_diagnostic "Versions of critical dependencies" check_web_server_version - check_web_server_version + check_resolver_server_version check_php_version } @@ -428,14 +450,45 @@ check_required_ports() { # Sort the addresses and remove duplicates while IFS= read -r line; do ports_in_use+=( "$line" ) - done < <( lsof -i -P -n | awk -F' ' '/LISTEN/ {print $9, $1}' | sort | uniq | cut -d':' -f2 ) + done < <( lsof -i -P -n | awk -F' ' '/LISTEN/ {print $9, $1}' | sort -n | uniq | cut -d':' -f2 ) # Now that we have the values stored, for i in ${!ports_in_use[@]}; do local port_number="$(echo "${ports_in_use[$i]}" | awk '{print $1}')" local service_name=$(echo "${ports_in_use[$i]}" | awk '{print $2}') - # display the information nicely to the user - log_write " [${port_number}] is in use by ${service_name}" + case "${port_number}" in + 53) if [[ "${service_name}" == "dnsmasq" ]]; then + # if port 53 is dnsmasq, show it in green as it's standard + log_write " [${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" + # Otherwise, + else + # Show the service name in red since it's non-standard + log_write " [${COL_LIGHT_RED}${port_number}${COL_NC}] is in use by ${COL_LIGHT_RED}${service_name}${COL_NC} + Please see: ${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC}" + fi + ;; + 80) if [[ "${service_name}" == "lighttpd" ]]; then + # if port 53 is dnsmasq, show it in green as it's standard + log_write " [${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" + # Otherwise, + else + # Show the service name in red since it's non-standard + log_write " [${COL_LIGHT_RED}${port_number}${COL_NC}] is in use by ${COL_LIGHT_RED}${service_name}${COL_NC} + Please see: ${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC}" + fi + ;; + 4711) if [[ "${service_name}" == "pihole-FT" ]]; then + # if port 4711 is pihole-FTL, show it in green as it's standard + log_write " [${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" + # Otherwise, + else + # Show the service name in yellow since it's non-standard, but should still work + log_write " [${COL_YELLOW}${port_number}${COL_NC}] is in use by ${COL_YELLOW}${service_name}${COL_NC} + Please see: ${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC}" + fi + ;; + *) log_write " [${port_number}] is in use by ${service_name}"; + esac done } @@ -492,6 +545,8 @@ dig_at() { local local_dig local pihole_dig local remote_dig + # Use a static domain that we know has IPv4 and IPv6 to avoid false positives + local remote_url="doubleclick.com" # If the protocol (4 or 6) is 6, if [[ ${protocol} == "6" ]]; then @@ -519,7 +574,7 @@ dig_at() { # Otherwise, else # show a failure - log_write " ${CROSS} Failed to resolve ${random_url} via localhot (${local_address})" + log_write " ${CROSS} Failed to resolve ${random_url} via localhost (${local_address})" fi # Next we need to check if Pi-hole can resolve a domain when the query is sent to it's IP address @@ -534,9 +589,9 @@ dig_at() { # Finally, we need to make sure legitimate sites can out if using an external, public DNS server if remote_dig=$(dig -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then # If successful, the real IP of the domain will be returned instead of Pi-hole's IP - log_write " ${TICK} ${random_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" + log_write " ${TICK} ${remote_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" else - log_write " ${CROSS} Failed to resolve ${random_url} via a remote, public DNS server (${remote_address})" + log_write " ${CROSS} Failed to resolve ${remote_url} via a remote, public DNS server (${remote_address})" fi } @@ -551,7 +606,11 @@ process_status(){ # get it's status local status_of_process=$(systemctl is-active "${i}") # and print it out to the user - log_write " [i] ${i} daemon is ${status_of_process}" + if [[ "${status_of_process}" == "active" ]]; then + log_write " ${TICK} ${COL_LIGHT_GREEN}${i}${COL_NC} daemon is ${COL_LIGHT_GREEN}${status_of_process}${COL_NC}" + else + log_write " ${TICK} ${COL_LIGHT_RED}${i}${COL_NC} daemon is ${COL_LIGHT_RED}${status_of_process}${COL_NC}" + fi done } @@ -628,7 +687,7 @@ list_files_in_dir() { for each_file in "${files_found[@]}"; do # display the information with the ${INFO} icon # Also print the permissions and the user/group - log_write " ${INFO} ${each_file} ( $(ls -ld ${dir_to_parse}/${each_file} | awk '{print $1, $3, $4}') )" + log_write " ${INFO} $(ls -ld ${dir_to_parse}/${each_file})" done } @@ -682,7 +741,7 @@ tricorder_nc_or_ssl() { # Check fist for openssl since encryption is a good thing if command -v openssl &> /dev/null; then # If successful - log_write " ${INFO} Using openssl for transmission." + log_write " * Using openssl for transmission." # transmit the log and store the token returned in the tricorder variable tricorder=$(cat /var/log/pihole_debug.log | openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null) # Otherwise, @@ -701,11 +760,11 @@ upload_to_tricorder() { # Let the user know debugging is complete echo "" - log_write "${TICK} Finshed debugging!" + log_write "${TICK} Finished debugging!" # Provide information on what they should do with their token - log_write " ${INFO} The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." - log_write " For more information, see: https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/" + log_write " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." + log_write " * For more information, see: https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/" # If pihole -d is running automatically (usually throught the dashboard) if [[ "${AUTOMATED}" ]]; then # let the user know @@ -746,7 +805,7 @@ upload_to_tricorder() { log_write " Please try again or contact the Pi-hole team for assistance." fi echo "" - log_write " A local copy of the debug log can be found at : /var/log/pihole_debug.log" + log_write " A local copy of the debug log can be found at : /var/log/pihole_debug.log" echo "" } From 7873da1ae57c61fb330d7128d85bfbfb37cce4bf Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Fri, 26 May 2017 15:17:26 -0500 Subject: [PATCH 050/162] more colors. shortened dig timeouts --- advanced/Scripts/piholeDebug.sh | 74 ++++++++++++++++----------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 5691b6af..66c2ebef 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -153,13 +153,13 @@ check_core_version() { # If not, else # pring the current version in yellow - log_write " ${INFO} Core: ${COL_YELLOW}${PI_HOLE_VERSION:-Untagged}${COL_NC} (See ${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC} on how to update Pi-hole)" + log_write " ${INFO} Core: ${COL_YELLOW}${PI_HOLE_VERSION:-Untagged}${COL_NC} (${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC})" fi if [[ "${PI_HOLE_BRANCH}" == "master" ]]; then log_write " ${INFO} Branch: ${COL_LIGHT_GREEN}${PI_HOLE_BRANCH}${COL_NC}" else - log_write " ${INFO} Branch: ${COL_YELLOW}${PI_HOLE_BRANCH:-Detached}${COL_NC} (See ${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC} for more information)" + log_write " ${INFO} Branch: ${COL_YELLOW}${PI_HOLE_BRANCH:-Detached}${COL_NC} (${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC})" fi log_write " ${INFO} Commit: ${PI_HOLE_COMMIT}" # If git status failed, @@ -193,13 +193,13 @@ check_web_version() { if [[ "${WEB_VERSION}" == "$(pihole -v | awk '/AdminLTE/ {print $6}' | cut -d ')' -f1)" ]]; then log_write " ${TICK} Web: ${COL_LIGHT_GREEN}${WEB_VERSION}${COL_NC}" else - log_write " ${INFO} Web: ${COL_YELLOW}${WEB_VERSION:-Untagged}${COL_NC} (See ${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC} on how to update Pi-hole)" + log_write " ${INFO} Web: ${COL_YELLOW}${WEB_VERSION:-Untagged}${COL_NC} (${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC})" fi if [[ "${WEB_BRANCH}" == "master" ]]; then log_write " ${TICK} Branch: ${COL_LIGHT_GREEN}${WEB_BRANCH}${COL_NC}" else - log_write " ${INFO} Branch: ${COL_YELLOW}${WEB_BRANCH:-Detached}${COL_NC} (See ${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC} for more information)" + log_write " ${INFO} Branch: ${COL_YELLOW}${WEB_BRANCH:-Detached}${COL_NC} (${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC})" fi log_write " ${INFO} Commit: ${WEB_COMMIT}" # If git status failed, @@ -224,16 +224,14 @@ check_web_server_version() { WEB_SERVER="lighttpd" # Parse out just the version number WEB_SERVER_VERSON="$(lighttpd -v |& head -n1 | cut -d '/' -f2 | cut -d ' ' -f1)" - # Display the information to the user - log_write " ${INFO} ${WEB_SERVER}" # If the Web server does not have a version (the variable is empty) if [[ -z "${WEB_SERVER_VERSON}" ]]; then # Display and error - log_write " ${CROSS} ${WEB_SERVER} version could not be detected." + log_write " ${CROSS} ${WEB_SERVER} version could not be detected." # Otherwise, else # display the version - log_write " ${TICK} ${WEB_SERVER_VERSON}" + log_write " ${TICK} ${WEB_SERVER}: ${WEB_SERVER_VERSON}" fi } @@ -243,32 +241,28 @@ check_resolver_server_version() { RESOLVER="dnsmasq" # Parse out just the version number RESOVLER_VERSON="$(dnsmasq -v |& head -n1 | awk '{print $3}')" - # Display the information to the user - log_write " ${INFO} ${RESOLVER}" # If the DNS server does not have a version (the variable is empty) if [[ -z "${RESOVLER_VERSON}" ]]; then # Display and error - log_write " ${CROSS} ${RESOLVER} version could not be detected." + log_write " ${CROSS} ${RESOLVER} version could not be detected." # Otherwise, else # display the version - log_write " ${TICK} ${RESOVLER_VERSON}" + log_write " ${TICK} ${RESOLVER}: ${RESOVLER_VERSON}" fi } check_php_version() { # Parse out just the version number PHP_VERSION=$(php -v |& head -n1 | cut -d '-' -f1 | cut -d ' ' -f2) - # Display the info to the user - log_write " ${INFO} PHP" # If no version is detected, if [[ -z "${PHP_VERSION}" ]]; then # show an error - log_write " ${CROSS} PHP version could not be detected." + log_write " ${CROSS} PHP version could not be detected." # otherwise, else # Show the version - log_write " ${TICK} ${PHP_VERSION}" + log_write " ${TICK} PHP: ${PHP_VERSION}" fi } @@ -392,19 +386,19 @@ ping_gateway() { # If the gateway variable has a value (meaning a gateway was found), if [[ -n "${gateway}" ]]; then # Let the user know we will ping the gateway for a response - log_write " ${INFO} Trying three pings on IPv${protocol} gateway at ${gateway}..." + log_write " * Trying three pings on IPv${protocol} gateway at ${gateway}..." # Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only, # on the pihole interface, and tail the last three lines of the output # If pinging the gateway is not successful, if ! ping_cmd="$(${cmd} -q -c 3 -W 3 -n ${gateway} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then # let the user know - log_write " ${CROSS} Gateway did not respond." + log_write " ${CROSS} ${COL_LIGHT_RED}Gateway did not respond.${COL_NC}" # and return an error code return 1 # Otherwise, else # show a success - log_write " ${TICK} Gateway responded." + log_write " ${TICK} ${COL_LIGHT_GREEN}Gateway responded.${COL_NC}" # and return a success code return 0 fi @@ -517,18 +511,18 @@ check_x_headers() { # If the X-header found by curl matches what is should be, if [[ $block_page == $block_page_working ]]; then # display a success message - log_write " $TICK ${block_page}" + log_write " $TICK ${COL_LIGHT_GREEN}${block_page}${COL_NC}" # Otherwise, else # show an error - log_write " $CROSS X-Header does not match or could not be retrieved" + log_write " $CROSS ${COL_LIGHT_RED}X-Header does not match or could not be retrieved.${COL_NC}" fi # Same logic applies to the dashbord as above if [[ $dashboard == $dashboard_working ]]; then - log_write " $TICK ${dashboard}" + log_write " $TICK ${COL_LIGHT_GREEN}${dashboard}${COL_NC}" else - log_write " $CROSS X-Header does not match or could not be retrieved" + log_write " $CROSS ${COL_LIGHT_RED}X-Header does not match or could not be retrieved.${COL_NC}" fi } @@ -568,30 +562,30 @@ dig_at() { local random_url=$(shuf -n 1 "${GRAVITYFILE}" | awk -F ' ' '{ print $2 }') # First do a dig on localhost, to see if Pi-hole can use itself to block a domain - if local_dig=$(dig -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then + if local_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then # If it can, show sucess - log_write " ${TICK} ${random_url} is ${local_dig} via localhost (${local_address})" + log_write " ${TICK} ${COL_LIGHT_GREEN}${random_url} is ${local_dig}${COL_NC} via localhost (${local_address})" # Otherwise, else # show a failure - log_write " ${CROSS} Failed to resolve ${random_url} via localhost (${local_address})" + log_write " ${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} ${COL_LIGHT_RED}via localhost${COL_NC} (${local_address})" fi # Next we need to check if Pi-hole can resolve a domain when the query is sent to it's IP address # This better emulates how clients will interact with Pi-hole as opposed to above where Pi-hole is # just asing itself locally - if pihole_dig=$(dig -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then - log_write " ${TICK} ${random_url} is ${pihole_dig} via Pi-hole (${pihole_address})" + if pihole_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then + log_write " ${TICK} ${COL_LIGHT_GREEN}${random_url} is ${pihole_dig}${COL_NC} via Pi-hole (${pihole_address})" else - log_write " ${CROSS} Failed to resolve ${random_url} via Pi-hole (${pihole_address})" + log_write " ${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} ${COL_LIGHT_RED}via Pi-hole${COL_NC} (${pihole_address})" fi # Finally, we need to make sure legitimate sites can out if using an external, public DNS server - if remote_dig=$(dig -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then + if remote_dig=$(dig +tries=1 +time=2 -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then # If successful, the real IP of the domain will be returned instead of Pi-hole's IP - log_write " ${TICK} ${remote_url} is ${remote_dig} via a remote, public DNS server (${remote_address})" + log_write " ${TICK} ${COL_LIGHT_GREEN}${remote_url} is ${remote_dig}${COL_NC} via a remote, public DNS server (${remote_address})" else - log_write " ${CROSS} Failed to resolve ${remote_url} via a remote, public DNS server (${remote_address})" + log_write " ${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${remote_url} ${COL_LIGHT_RED}via a remote, public DNS server${COL_NC} (${remote_address})" fi } @@ -609,7 +603,7 @@ process_status(){ if [[ "${status_of_process}" == "active" ]]; then log_write " ${TICK} ${COL_LIGHT_GREEN}${i}${COL_NC} daemon is ${COL_LIGHT_GREEN}${status_of_process}${COL_NC}" else - log_write " ${TICK} ${COL_LIGHT_RED}${i}${COL_NC} daemon is ${COL_LIGHT_RED}${status_of_process}${COL_NC}" + log_write " ${CROSS} ${COL_LIGHT_RED}${i}${COL_NC} daemon is ${COL_LIGHT_RED}${status_of_process}${COL_NC}" fi done } @@ -741,13 +735,13 @@ tricorder_nc_or_ssl() { # Check fist for openssl since encryption is a good thing if command -v openssl &> /dev/null; then # If successful - log_write " * Using openssl for transmission." + log_write " * Using ${COL_LIGHT_GREEN}openssl${COL_NC} for transmission." # transmit the log and store the token returned in the tricorder variable tricorder=$(cat /var/log/pihole_debug.log | openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null) # Otherwise, else # use net cat - log_write " ${INFO} Using netcat for transmission." + log_write " ${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999) fi } @@ -764,17 +758,19 @@ upload_to_tricorder() { # Provide information on what they should do with their token log_write " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." - log_write " * For more information, see: https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/" + log_write " * For more information, see: ${COL_CYAN}https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/${COL_NC}" + log_write "" + log_write " * If available, we'll use openssl to upload the log, otherwise it will fall back to netcat." # If pihole -d is running automatically (usually throught the dashboard) if [[ "${AUTOMATED}" ]]; then # let the user know log_write " ${INFO} Debug script running in automated mode" # and then decide again which tool to use to submit it if command -v openssl &> /dev/null; then - log_write " ${INFO} Using openssl for transmission." + log_write " ${INFO} Using ${COL_LIGHT_GREEN}openssl${COL_NC} for transmission." openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin else - log_write " ${INFO} Using netcat for transmission." + log_write " ${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." nc tricorder.pi-hole.net 9999 < /dev/stdin fi else @@ -786,7 +782,7 @@ upload_to_tricorder() { # If they say yes, run our function for uploading the log [yY][eE][sS]|[yY]) tricorder_nc_or_ssl;; # If they choose no, just exit out of the script - *) log_write " ${INFO} Log will NOT be uploaded to tricorder.";exit; + *) log_write " * Log will NOT be uploaded to tricorder.";exit; esac fi # Check if tricorder.pi-hole.net is reachable and provide token From 7ec169ab10fb5e99eeb8a0c0905acae9c10dc861 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Fri, 26 May 2017 22:05:50 -0500 Subject: [PATCH 051/162] more comments, fixed automated tricorder, variablizing echos, verify FTL version --- advanced/Scripts/piholeDebug.sh | 196 +++++++++++++++++++------------- 1 file changed, 118 insertions(+), 78 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 66c2ebef..af9802a9 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -36,6 +36,10 @@ WHITELISTMATCHES="/tmp/whitelistmatches.list" readonly FTLLOG="/var/log/pihole-FTL.log" coltable=/opt/pihole/COL_TABLE +# FAQ URLs +FAQ_UPDATE_PI_HOLE="https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249" +FAQ_CHECKOUT_COMMAND="https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout" + # These provide the colors we need for making the log more readable if [[ -f ${coltable} ]]; then source ${coltable} @@ -87,7 +91,8 @@ echo_succes_or_fail() { initiate_debug() { # Clear the screen so the debug log is readable clear - log_write "${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC}" 2>&1 | tee "${DEBUG_LOG}" + # Display that the debug process is beginning + log_write "${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC}" # Timestamp the start of the log log_write " ${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initiated." } @@ -97,6 +102,7 @@ initiate_debug() { # Colors do not show in the dasboard, but the icons do: [i], [✓], and [✗] echo_current_diagnostic() { # Colors are used for visually distinguishing each test in the output + # These colors do not show in the GUI, but the formatting will log_write "\n${COL_LIGHT_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}" } @@ -126,9 +132,9 @@ if_directory_exists() { fi } +# Checks the core version of the Pi-hole codebase check_core_version() { - # Checks the core version of the Pi-hole codebase - echo_current_diagnostic "Pi-hole Versions" + echo_current_diagnostic "Pi-hole versions" # Store the error message in a variable in case we want to change and/or reuse it local error_msg="git status failed" # If the pihole git directory exists, @@ -152,15 +158,21 @@ check_core_version() { log_write " ${TICK} Core: ${COL_LIGHT_GREEN}${PI_HOLE_VERSION}${COL_NC}" # If not, else - # pring the current version in yellow - log_write " ${INFO} Core: ${COL_YELLOW}${PI_HOLE_VERSION:-Untagged}${COL_NC} (${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC})" + # echo the current version in yellow, signifying it's something to take a look at, but not a critical error + # Also add a URL to an FAQ + log_write " ${INFO} Core: ${COL_YELLOW}${PI_HOLE_VERSION:-Untagged}${COL_NC} (${COL_CYAN}${FAQ_UPDATE_PI_HOLE}${COL_NC})" fi + # If the repo is on the master branch, they are on the stable codebase if [[ "${PI_HOLE_BRANCH}" == "master" ]]; then + # so the color of the text is green log_write " ${INFO} Branch: ${COL_LIGHT_GREEN}${PI_HOLE_BRANCH}${COL_NC}" + # If it is any other branch, they are in a developement branch else - log_write " ${INFO} Branch: ${COL_YELLOW}${PI_HOLE_BRANCH:-Detached}${COL_NC} (${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC})" + # So show that in yellow, signifying it's something to take a look at, but not a critical error + log_write " ${INFO} Branch: ${COL_YELLOW}${PI_HOLE_BRANCH:-Detached}${COL_NC} (${COL_CYAN}${FAQ_CHECKOUT_COMMAND}${COL_NC})" fi + # echo the current commit log_write " ${INFO} Commit: ${PI_HOLE_COMMIT}" # If git status failed, else @@ -189,18 +201,27 @@ check_web_version() { WEB_BRANCH=$(git rev-parse --abbrev-ref HEAD); # The commit they are on WEB_COMMIT=$(git describe --long --dirty --tags --always) - # echo this information out to the user in a nice format + # If the Web version reported by pihole -v matches the current version if [[ "${WEB_VERSION}" == "$(pihole -v | awk '/AdminLTE/ {print $6}' | cut -d ')' -f1)" ]]; then + # echo it in green log_write " ${TICK} Web: ${COL_LIGHT_GREEN}${WEB_VERSION}${COL_NC}" + # Otherwise, else - log_write " ${INFO} Web: ${COL_YELLOW}${WEB_VERSION:-Untagged}${COL_NC} (${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC})" + # Show it in yellow with a link to update Pi-hole + log_write " ${INFO} Web: ${COL_YELLOW}${WEB_VERSION:-Untagged}${COL_NC} (${COL_CYAN}${FAQ_UPDATE_PI_HOLE}${COL_NC})" fi + + # If the repo is on the master branch, they are on the stable codebase if [[ "${WEB_BRANCH}" == "master" ]]; then + # so the color of the text is green log_write " ${TICK} Branch: ${COL_LIGHT_GREEN}${WEB_BRANCH}${COL_NC}" else - log_write " ${INFO} Branch: ${COL_YELLOW}${WEB_BRANCH:-Detached}${COL_NC} (${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC})" + # If it is any other branch, they are in a developement branch + # So show that in yellow, signifying it's something to take a look at, but not a critical error + log_write " ${INFO} Branch: ${COL_YELLOW}${WEB_BRANCH:-Detached}${COL_NC} (${COL_CYAN}${FAQ_CHECKOUT_COMMAND}${COL_NC})" fi + # echo the current commit log_write " ${INFO} Commit: ${WEB_COMMIT}" # If git status failed, else @@ -214,8 +235,14 @@ check_web_version() { check_ftl_version() { # Use the built in command to check FTL's version FTL_VERSION=$(pihole-FTL version) - # and display it to the user - log_write " ${INFO} FTL: ${FTL_VERSION}" + # Compare the current FTL version to the remote version + if [[ "${FTL_VERSION}" == "$(pihole -v | awk '/FTL/ {print $6}' | cut -d ')' -f1)" ]]; then + # If they are the same, FTL is up-to-date + log_write " ${TICK} FTL: ${COL_LIGHT_GREEN}${FTL_VERSION}${COL_NC}" + else + # If not, show it in yellow, signifying there is an update + log_write " ${TICK} FTL: ${COL_YELLOW}${FTL_VERSION}${COL_NC}" + fi } # Check the current version of the Web server @@ -227,10 +254,9 @@ check_web_server_version() { # If the Web server does not have a version (the variable is empty) if [[ -z "${WEB_SERVER_VERSON}" ]]; then # Display and error - log_write " ${CROSS} ${WEB_SERVER} version could not be detected." - # Otherwise, + log_write " ${CROSS} ${COL_LIGHT_RED}${WEB_SERVER} version could not be detected.${COL_NC}" else - # display the version + # Otherwise, display the version log_write " ${TICK} ${WEB_SERVER}: ${WEB_SERVER_VERSON}" fi } @@ -244,10 +270,9 @@ check_resolver_server_version() { # If the DNS server does not have a version (the variable is empty) if [[ -z "${RESOVLER_VERSON}" ]]; then # Display and error - log_write " ${CROSS} ${RESOLVER} version could not be detected." - # Otherwise, + log_write " ${CROSS} ${COL_LIGHT_RED}${RESOLVER} version could not be detected.${COL_NC}" else - # display the version + # Otherwise, display the version log_write " ${TICK} ${RESOLVER}: ${RESOVLER_VERSON}" fi } @@ -258,19 +283,18 @@ check_php_version() { # If no version is detected, if [[ -z "${PHP_VERSION}" ]]; then # show an error - log_write " ${CROSS} PHP version could not be detected." - # otherwise, + log_write " ${CROSS} ${COL_LIGHT_RED}PHP version could not be detected.${COL_NC}" else - # Show the version + # Otherwise, show the version log_write " ${TICK} PHP: ${PHP_VERSION}" fi - } # These are the most critical dependencies of Pi-hole, so we check for them # and their versions, using the functions above. check_critical_dependencies() { echo_current_diagnostic "Versions of critical dependencies" + # Use the function created earlier and bundle them into one function that checks all the version numbers check_web_server_version check_resolver_server_version check_php_version @@ -287,14 +311,16 @@ get_distro_attributes() { local distro_attribute # For each line found in an /etc/*release file, for distro_attribute in "${distro_info[@]}"; do - # display the information with the ${INFO} icon - pretty_name_key=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f1) - # we need just the OS PRETTY_NAME, so print it when we find it + # store the key in a variable + local pretty_name_key=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f1) + # we need just the OS PRETTY_NAME, if [[ "${pretty_name_key}" == "PRETTY_NAME" ]]; then - PRETTY_NAME=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f2- | tr -d '"') - log_write " ${INFO} ${PRETTY_NAME}" - # Otherwise, do nothing + # so print it when we find it + PRETTY_NAME_VALUE=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f2- | tr -d '"') + # and then echoed out to the screen + log_write " ${INFO} ${PRETTY_NAME_VALUE}" else + # Since we only need the pretty name, we can just skip over anything that is not a match : fi done @@ -304,7 +330,7 @@ get_distro_attributes() { diagnose_operating_system() { # local variable for system requirements - local faq_url="https://discourse.pi-hole.net/t/hardware-software-requirements/273" + FAQ_HARDWARE_REQUIREMENTS="https://discourse.pi-hole.net/t/hardware-software-requirements/273" # error message in a variable so we can easily modify it later (or re-use it) local error_msg="Distribution unknown -- most likely you are on an unsupported platform and may run into issues." # Display the current test that is running @@ -315,8 +341,7 @@ diagnose_operating_system() { # display the attributes to the user from the function made earlier get_distro_attributes || \ # If it doesn't exist, it's not a system we currently support and link to FAQ - log_write " ${CROSS} ${COL_LIGHT_RED}${error_msg}${COL_NC} - ${INFO} ${COL_LIGHT_RED}Please see${COL_NC}: ${COL_CYAN}${faq_url}${COL_NC}" + log_write " ${CROSS} ${COL_LIGHT_RED}${error_msg}${COL_NC} (${COL_CYAN}${FAQ_HARDWARE_REQUIREMENTS}${COL_NC})" } processor_check() { @@ -326,10 +351,9 @@ processor_check() { # If it does not contain a value, if [[ -z "${PROCESSOR}" ]]; then # we couldn't detect it, so show an error - log_write " ${CROSS} Processor could not be identified." - # Otherwise, + log_write " ${CROSS} ${COL_LIGHT_RED}Processor could not be identified.${COL_NC}" else - # Show the processor type + # Otherwise, show the processor type log_write " ${INFO} ${PROCESSOR}" fi } @@ -353,10 +377,9 @@ detect_ip_addresses() { # For each one in the list, print it out using the iterator as a numbered list log_write " [$i] ${ip_addr_list[$i]}" done - # Othwerwise, else - # explain that the protocol is not configured - log_write " ${CROSS} No IPv${protocol} found on ${PIHOLE_INTERFACE}" + # If there are no IPs detected, explain that the protocol is not configured + log_write " ${CROSS} ${COL_LIGHT_RED}No IPv${protocol} found on ${PIHOLE_INTERFACE}${COL_NC}" return 1 fi } @@ -371,9 +394,8 @@ ping_gateway() { local cmd="ping6" # and Google's public IPv6 address local public_address="2001:4860:4860::8888" - # Otherwise, else - # use ping + # Otherwise, just use ping local cmd="ping" # and Google's public IPv4 address local public_address="8.8.8.8" @@ -406,7 +428,7 @@ ping_gateway() { } ping_internet() { - # Give the first argument a readable name + # Give the first argument a readable name (a 4 or a six should be the argument) local protocol="${1}" # If the protocol is 6, if [[ ${protocol} == "6" ]]; then @@ -414,9 +436,8 @@ ping_internet() { local cmd="ping6" # and Google's public IPv6 address local public_address="2001:4860:4860::8888" - # Otherwise, else - # use ping + # Otherwise, just use ping local cmd="ping" # and Google's public IPv4 address local public_address="8.8.8.8" @@ -425,12 +446,11 @@ ping_internet() { # Try to ping the address 3 times if ! ping_inet="$(${cmd} -q -W 3 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then # if it's unsuccessful, show an error - log_write " ${CROSS} Cannot reach the Internet" + log_write " ${CROSS} ${COL_LIGHT_RED}Cannot reach the Internet.${COL_NC}" return 1 - # Otherwise, else - # show success - log_write " ${TICK} Query responded." + # Otherwise, show success + log_write " ${TICK} ${COL_LIGHT_GREEN}Query responded.${COL_NC}" return 0 fi } @@ -448,8 +468,10 @@ check_required_ports() { # Now that we have the values stored, for i in ${!ports_in_use[@]}; do + # loop through them and assign some local variables local port_number="$(echo "${ports_in_use[$i]}" | awk '{print $1}')" local service_name=$(echo "${ports_in_use[$i]}" | awk '{print $2}') + # Use a case statement to determine if the right services are using the right ports case "${port_number}" in 53) if [[ "${service_name}" == "dnsmasq" ]]; then # if port 53 is dnsmasq, show it in green as it's standard @@ -512,23 +534,24 @@ check_x_headers() { if [[ $block_page == $block_page_working ]]; then # display a success message log_write " $TICK ${COL_LIGHT_GREEN}${block_page}${COL_NC}" - # Otherwise, else - # show an error + # Otherwise, show an error log_write " $CROSS ${COL_LIGHT_RED}X-Header does not match or could not be retrieved.${COL_NC}" fi - # Same logic applies to the dashbord as above + # Same logic applies to the dashbord as above, if the X-Header matches what a working system shoud have, if [[ $dashboard == $dashboard_working ]]; then + # then we can show a success log_write " $TICK ${COL_LIGHT_GREEN}${dashboard}${COL_NC}" else + # Othewise, it's a failure since the X-Headers either don't exist or have been modified in some way log_write " $CROSS ${COL_LIGHT_RED}X-Header does not match or could not be retrieved.${COL_NC}" fi } dig_at() { - # We need to test if Pi-hole can properly resolve domain names as it is an - # essential piece of the software that needs to work + # We need to test if Pi-hole can properly resolve domain names + # as it is an essential piece of the software # Store the arguments as variables with names local protocol="${1}" @@ -540,6 +563,7 @@ dig_at() { local pihole_dig local remote_dig # Use a static domain that we know has IPv4 and IPv6 to avoid false positives + # Sometimes the randomly chosen domains don't use IPv6, or something else is wrong with them local remote_url="doubleclick.com" # If the protocol (4 or 6) is 6, @@ -559,32 +583,40 @@ dig_at() { fi # Find a random blocked url that has not been whitelisted. + # This helps emulate queries to different domains that a user might query + # It will also give extra assurance that Pi-hole is correctly resolving and blocking domains local random_url=$(shuf -n 1 "${GRAVITYFILE}" | awk -F ' ' '{ print $2 }') - # First do a dig on localhost, to see if Pi-hole can use itself to block a domain + # First, do a dig on localhost to see if Pi-hole can use itself to block a domain if local_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then # If it can, show sucess log_write " ${TICK} ${COL_LIGHT_GREEN}${random_url} is ${local_dig}${COL_NC} via localhost (${local_address})" - # Otherwise, else - # show a failure + # Otherwise, show a failure log_write " ${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} ${COL_LIGHT_RED}via localhost${COL_NC} (${local_address})" fi # Next we need to check if Pi-hole can resolve a domain when the query is sent to it's IP address # This better emulates how clients will interact with Pi-hole as opposed to above where Pi-hole is # just asing itself locally + # The default timeouts and tries are reduced in case the DNS server isn't working, so the user isn't waiting for too long + + # If Pi-hole can dig itself from it's IP (not the loopback address) if pihole_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then + # show a success log_write " ${TICK} ${COL_LIGHT_GREEN}${random_url} is ${pihole_dig}${COL_NC} via Pi-hole (${pihole_address})" else + # Othewise, show a failure log_write " ${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} ${COL_LIGHT_RED}via Pi-hole${COL_NC} (${pihole_address})" fi - # Finally, we need to make sure legitimate sites can out if using an external, public DNS server + # Finally, we need to make sure legitimate queries can out to the Internet using an external, public DNS server + # We are using the static remote_url here instead of a random one because we know it works with IPv4 and IPv6 if remote_dig=$(dig +tries=1 +time=2 -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then # If successful, the real IP of the domain will be returned instead of Pi-hole's IP log_write " ${TICK} ${COL_LIGHT_GREEN}${remote_url} is ${remote_dig}${COL_NC} via a remote, public DNS server (${remote_address})" else + # Otherwise, show an error log_write " ${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${remote_url} ${COL_LIGHT_RED}via a remote, public DNS server${COL_NC} (${remote_address})" fi } @@ -594,22 +626,25 @@ process_status(){ echo_current_diagnostic "Pi-hole processes" # Store them in an array for easy use PROCESSES=( dnsmasq lighttpd pihole-FTL ) + # Local iterator local i # For each process, for i in "${PROCESSES[@]}"; do - # get it's status + # get its status local status_of_process=$(systemctl is-active "${i}") # and print it out to the user if [[ "${status_of_process}" == "active" ]]; then + # If it's active, show it in green log_write " ${TICK} ${COL_LIGHT_GREEN}${i}${COL_NC} daemon is ${COL_LIGHT_GREEN}${status_of_process}${COL_NC}" else + # If it's not, show it in red log_write " ${CROSS} ${COL_LIGHT_RED}${i}${COL_NC} daemon is ${COL_LIGHT_RED}${status_of_process}${COL_NC}" fi done } parse_file() { - # Set the first argument passed to tihs function as a named variable for better readability + # Set the first argument passed to this function as a named variable for better readability local filename="${1}" # Put the current Internal Field Separator into another variable so it can be restored later OLD_IFS="$IFS" @@ -618,7 +653,7 @@ parse_file() { # Set a named variable for better readability local file_lines - # For each lin in the file, + # For each line in the file, for file_lines in "${file_info[@]}"; do # display the information with the ${INFO} icon log_write " ${INFO} ${file_lines}" @@ -633,13 +668,13 @@ diagnose_setup_variables() { # If the variable file exists, file_exists "${VARSFILE}" && \ + log_write " * Sourcing ${VARSFILE}..."; # source it source ${VARSFILE}; - log_write " ${INFO} Sourcing ${VARSFILE}..."; # and display a green check mark with ${DONE} - echo_succes_or_fail "${VARSFILE} is readable and has been sourced." || \ + echo_succes_or_fail "${COL_LIGHT_GREEN}${VARSFILE}${COL_NC} is readable and ${COL_LIGHT_GREEN}has been sourced.${COL_NC}" || \ # Othwerwise, error out - echo_succes_or_fail "${VARSFILE} is not readable. + echo_succes_or_fail "${VARSFILE} ${COL_LIGHT_RED}is not readable.${COL_NC} ${INFO} $(ls -l ${VARSFILE} 2>/dev/null)"; parse_file "${VARSFILE}" } @@ -648,8 +683,9 @@ check_name_resolution() { # Check name resoltion from localhost, Pi-hole's IP, and Google's name severs # using the function we created earlier dig_at 4 "${IPV4_ADDRESS%/*}" - # If IPv6 enabled, check resolution + # If IPv6 enabled, if [[ "${IPV6_ADDRESS}" ]]; then + # check resolution dig_at 6 "${IPV6_ADDRESS%/*}" fi } @@ -668,7 +704,7 @@ dir_check() { # show a success message echo_succes_or_fail "Files detected" || \ # Otherwise, show an error - echo_succes_or_fail "directory does not exist" + echo_succes_or_fail "${COL_LIGHT_RED}irectory does not exist.${COL_NC}" done } @@ -683,7 +719,6 @@ list_files_in_dir() { # Also print the permissions and the user/group log_write " ${INFO} $(ls -ld ${dir_to_parse}/${each_file})" done - } check_dnsmasq_d() { @@ -723,26 +758,28 @@ check_http_directory() { } analyze_gravity_list() { + echo_current_diagnostic "Gravity list" # It's helpful to know how big a user's gravity file is gravity_length=$(grep -c ^ "${GRAVITYFILE}") && \ - log_write " ${INFO} ${GRAVITYFILE} is ${gravity_length} lines long." || \ + log_write " ${INFO} ${GRAVITYFILE} is ${gravity_length} lines long."; + parse_file ${GRAVITYFILE} || \ # If the previous command failed, something is wrong with the file - log_write " ${CROSS} ${GRAVITYFILE} not found!" + log_write " ${CROSS} ${COL_LIGHT_RED}${GRAVITYFILE} not found!${COL_NC}" } -tricorder_nc_or_ssl() { - # Users can submit their debug logs using nc (unencrypted) or opensll (enrypted) if available - # Check fist for openssl since encryption is a good thing +tricorder_use_nc_or_ssl() { + # Users can submit their debug logs using nc (unencrypted) or openssl (enrypted) if available + # Check for openssl first since encryption is a good thing if command -v openssl &> /dev/null; then - # If successful + # If the command exists, log_write " * Using ${COL_LIGHT_GREEN}openssl${COL_NC} for transmission." - # transmit the log and store the token returned in the tricorder variable - tricorder=$(cat /var/log/pihole_debug.log | openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null) + # encrypt and transmit the log and store the token returned in a variable + tricorder_token=$(cat ${DEBUG_LOG} | openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null) # Otherwise, else # use net cat log_write " ${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." - tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999) + tricorder_token=$(cat ${DEBUG_LOG} | nc tricorder.pi-hole.net 9999) fi } @@ -768,10 +805,10 @@ upload_to_tricorder() { # and then decide again which tool to use to submit it if command -v openssl &> /dev/null; then log_write " ${INFO} Using ${COL_LIGHT_GREEN}openssl${COL_NC} for transmission." - openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin + tricorder_token=$(openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin) else log_write " ${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." - nc tricorder.pi-hole.net 9999 < /dev/stdin + tricorder_token=$(nc tricorder.pi-hole.net 9999 < /dev/stdin) fi else echo "" @@ -780,22 +817,24 @@ upload_to_tricorder() { read -r -p "[?] Would you like to upload the log? [y/N] " response case ${response} in # If they say yes, run our function for uploading the log - [yY][eE][sS]|[yY]) tricorder_nc_or_ssl;; + [yY][eE][sS]|[yY]) tricorder_use_nc_or_ssl;; # If they choose no, just exit out of the script - *) log_write " * Log will NOT be uploaded to tricorder.";exit; + *) log_write " * Log will ${COL_LIGHT_GREE}NOT${COL_NC} be uploaded to tricorder.";exit; esac fi # Check if tricorder.pi-hole.net is reachable and provide token # along with some additional useful information - if [[ -n "${tricorder}" ]]; then + if [[ -n "${tricorder_token}" ]]; then echo "" log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" - log_write "${TICK} Your debug token is: ${COL_LIGHT_GREEN}${tricorder}${COL_NC}" + log_write "${TICK} Your debug token is: ${COL_LIGHT_GREEN}${tricorder_token}${COL_NC}" log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" log_write "" log_write " Provide this token to the Pi-hole team for assistance:" echo "" log_write " https://discourse.pi-hole.net" + echo "" + log_write " Your log will self-destruct after 48 hours." else log_write " ${CROSS} There was an error uploading your debug log." log_write " Please try again or contact the Pi-hole team for assistance." @@ -821,6 +860,7 @@ check_name_resolution process_status check_x_headers check_critical_dependencies +analyze_gravity_list check_dnsmasq_d check_lighttpd_d check_http_directory From 36907edd5002e5f7e586fb875070de1c6bfb19e5 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 27 May 2017 00:04:42 -0500 Subject: [PATCH 052/162] parse contents of each file in each dir, several log_writes --- advanced/Scripts/piholeDebug.sh | 201 +++++++++++++++++--------------- 1 file changed, 109 insertions(+), 92 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index af9802a9..86ee4e23 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -66,7 +66,7 @@ make_temporary_log() { } log_write() { - # echo arguments to both the log and the console" + # echo arguments to both the log and the console echo -e "${@}" | tee -a /proc/$$/fd/3 } @@ -76,15 +76,16 @@ copy_to_debug_log() { } echo_succes_or_fail() { - # Set the first argument passed to this function as a named variable for better readability - local message="${1}" # If the command was successful (a zero), if [[ $? -eq 0 ]]; then + # Set the first argument passed to this function as a named variable for better readability + local message="${1}" # show success - log_write " ${TICK} ${message}" + log_write "${TICK} ${message}" else + local message="${1}" # Otherwise, show a error - log_write " ${CROSS} ${message}" + log_write "${CROSS} ${message}" fi } @@ -94,7 +95,7 @@ initiate_debug() { # Display that the debug process is beginning log_write "${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC}" # Timestamp the start of the log - log_write " ${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initiated." + log_write "${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initiated." } # This is a function for visually displaying the curent test that is being run. @@ -155,25 +156,25 @@ check_core_version() { # echo this information out to the user in a nice format # If the current version matches what pihole -v produces, the user is up-to-date if [[ "${PI_HOLE_VERSION}" == "$(pihole -v | awk '/Pi-hole/ {print $6}' | cut -d ')' -f1)" ]]; then - log_write " ${TICK} Core: ${COL_LIGHT_GREEN}${PI_HOLE_VERSION}${COL_NC}" + log_write "${TICK} Core: ${COL_LIGHT_GREEN}${PI_HOLE_VERSION}${COL_NC}" # If not, else # echo the current version in yellow, signifying it's something to take a look at, but not a critical error # Also add a URL to an FAQ - log_write " ${INFO} Core: ${COL_YELLOW}${PI_HOLE_VERSION:-Untagged}${COL_NC} (${COL_CYAN}${FAQ_UPDATE_PI_HOLE}${COL_NC})" + log_write "${INFO} Core: ${COL_YELLOW}${PI_HOLE_VERSION:-Untagged}${COL_NC} (${COL_CYAN}${FAQ_UPDATE_PI_HOLE}${COL_NC})" fi # If the repo is on the master branch, they are on the stable codebase if [[ "${PI_HOLE_BRANCH}" == "master" ]]; then # so the color of the text is green - log_write " ${INFO} Branch: ${COL_LIGHT_GREEN}${PI_HOLE_BRANCH}${COL_NC}" + log_write "${INFO} Branch: ${COL_LIGHT_GREEN}${PI_HOLE_BRANCH}${COL_NC}" # If it is any other branch, they are in a developement branch else # So show that in yellow, signifying it's something to take a look at, but not a critical error - log_write " ${INFO} Branch: ${COL_YELLOW}${PI_HOLE_BRANCH:-Detached}${COL_NC} (${COL_CYAN}${FAQ_CHECKOUT_COMMAND}${COL_NC})" + log_write "${INFO} Branch: ${COL_YELLOW}${PI_HOLE_BRANCH:-Detached}${COL_NC} (${COL_CYAN}${FAQ_CHECKOUT_COMMAND}${COL_NC})" fi # echo the current commit - log_write " ${INFO} Commit: ${PI_HOLE_COMMIT}" + log_write "${INFO} Commit: ${PI_HOLE_COMMIT}\n" # If git status failed, else # Return an error message @@ -204,25 +205,25 @@ check_web_version() { # If the Web version reported by pihole -v matches the current version if [[ "${WEB_VERSION}" == "$(pihole -v | awk '/AdminLTE/ {print $6}' | cut -d ')' -f1)" ]]; then # echo it in green - log_write " ${TICK} Web: ${COL_LIGHT_GREEN}${WEB_VERSION}${COL_NC}" + log_write "${TICK} Web: ${COL_LIGHT_GREEN}${WEB_VERSION}${COL_NC}" # Otherwise, else # Show it in yellow with a link to update Pi-hole - log_write " ${INFO} Web: ${COL_YELLOW}${WEB_VERSION:-Untagged}${COL_NC} (${COL_CYAN}${FAQ_UPDATE_PI_HOLE}${COL_NC})" + log_write "${INFO} Web: ${COL_YELLOW}${WEB_VERSION:-Untagged}${COL_NC} (${COL_CYAN}${FAQ_UPDATE_PI_HOLE}${COL_NC})" fi # If the repo is on the master branch, they are on the stable codebase if [[ "${WEB_BRANCH}" == "master" ]]; then # so the color of the text is green - log_write " ${TICK} Branch: ${COL_LIGHT_GREEN}${WEB_BRANCH}${COL_NC}" + log_write "${TICK} Branch: ${COL_LIGHT_GREEN}${WEB_BRANCH}${COL_NC}" else # If it is any other branch, they are in a developement branch # So show that in yellow, signifying it's something to take a look at, but not a critical error - log_write " ${INFO} Branch: ${COL_YELLOW}${WEB_BRANCH:-Detached}${COL_NC} (${COL_CYAN}${FAQ_CHECKOUT_COMMAND}${COL_NC})" + log_write "${INFO} Branch: ${COL_YELLOW}${WEB_BRANCH:-Detached}${COL_NC} (${COL_CYAN}${FAQ_CHECKOUT_COMMAND}${COL_NC})" fi # echo the current commit - log_write " ${INFO} Commit: ${WEB_COMMIT}" + log_write "${INFO} Commit: ${WEB_COMMIT}\n" # If git status failed, else # Return an error message @@ -238,10 +239,10 @@ check_ftl_version() { # Compare the current FTL version to the remote version if [[ "${FTL_VERSION}" == "$(pihole -v | awk '/FTL/ {print $6}' | cut -d ')' -f1)" ]]; then # If they are the same, FTL is up-to-date - log_write " ${TICK} FTL: ${COL_LIGHT_GREEN}${FTL_VERSION}${COL_NC}" + log_write "${TICK} FTL: ${COL_LIGHT_GREEN}${FTL_VERSION}${COL_NC}" else # If not, show it in yellow, signifying there is an update - log_write " ${TICK} FTL: ${COL_YELLOW}${FTL_VERSION}${COL_NC}" + log_write "${TICK} FTL: ${COL_YELLOW}${FTL_VERSION}${COL_NC}" fi } @@ -254,10 +255,10 @@ check_web_server_version() { # If the Web server does not have a version (the variable is empty) if [[ -z "${WEB_SERVER_VERSON}" ]]; then # Display and error - log_write " ${CROSS} ${COL_LIGHT_RED}${WEB_SERVER} version could not be detected.${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}${WEB_SERVER} version could not be detected.${COL_NC}" else # Otherwise, display the version - log_write " ${TICK} ${WEB_SERVER}: ${WEB_SERVER_VERSON}" + log_write "${TICK} ${WEB_SERVER}: ${WEB_SERVER_VERSON}" fi } @@ -270,10 +271,10 @@ check_resolver_server_version() { # If the DNS server does not have a version (the variable is empty) if [[ -z "${RESOVLER_VERSON}" ]]; then # Display and error - log_write " ${CROSS} ${COL_LIGHT_RED}${RESOLVER} version could not be detected.${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}${RESOLVER} version could not be detected.${COL_NC}" else # Otherwise, display the version - log_write " ${TICK} ${RESOLVER}: ${RESOVLER_VERSON}" + log_write "${TICK} ${RESOLVER}: ${RESOVLER_VERSON}" fi } @@ -283,10 +284,10 @@ check_php_version() { # If no version is detected, if [[ -z "${PHP_VERSION}" ]]; then # show an error - log_write " ${CROSS} ${COL_LIGHT_RED}PHP version could not be detected.${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}PHP version could not be detected.${COL_NC}" else # Otherwise, show the version - log_write " ${TICK} PHP: ${PHP_VERSION}" + log_write "${TICK} PHP: ${PHP_VERSION}" fi } @@ -318,7 +319,7 @@ get_distro_attributes() { # so print it when we find it PRETTY_NAME_VALUE=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f2- | tr -d '"') # and then echoed out to the screen - log_write " ${INFO} ${PRETTY_NAME_VALUE}" + log_write "${INFO} ${PRETTY_NAME_VALUE}" else # Since we only need the pretty name, we can just skip over anything that is not a match : @@ -341,7 +342,7 @@ diagnose_operating_system() { # display the attributes to the user from the function made earlier get_distro_attributes || \ # If it doesn't exist, it's not a system we currently support and link to FAQ - log_write " ${CROSS} ${COL_LIGHT_RED}${error_msg}${COL_NC} (${COL_CYAN}${FAQ_HARDWARE_REQUIREMENTS}${COL_NC})" + log_write "${CROSS} ${COL_LIGHT_RED}${error_msg}${COL_NC} (${COL_CYAN}${FAQ_HARDWARE_REQUIREMENTS}${COL_NC})" } processor_check() { @@ -351,10 +352,10 @@ processor_check() { # If it does not contain a value, if [[ -z "${PROCESSOR}" ]]; then # we couldn't detect it, so show an error - log_write " ${CROSS} ${COL_LIGHT_RED}Processor could not be identified.${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}Processor could not be identified.${COL_NC}" else # Otherwise, show the processor type - log_write " ${INFO} ${PROCESSOR}" + log_write "${INFO} ${PROCESSOR}" fi } @@ -371,15 +372,16 @@ detect_ip_addresses() { # Local iterator local i # Display the protocol and interface - log_write " ${TICK} IPv${protocol} on ${PIHOLE_INTERFACE}" + log_write "${TICK} IPv${protocol} on ${PIHOLE_INTERFACE}" # Since there may be more than one IP address, store them in an array for i in "${!ip_addr_list[@]}"; do - # For each one in the list, print it out using the iterator as a numbered list - log_write " [$i] ${ip_addr_list[$i]}" + # For each one in the list, print it out + log_write "${ip_addr_list[$i]}" done + log_write "" else # If there are no IPs detected, explain that the protocol is not configured - log_write " ${CROSS} ${COL_LIGHT_RED}No IPv${protocol} found on ${PIHOLE_INTERFACE}${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}No IPv${protocol} found on ${PIHOLE_INTERFACE}${COL_NC}\n" return 1 fi } @@ -408,19 +410,19 @@ ping_gateway() { # If the gateway variable has a value (meaning a gateway was found), if [[ -n "${gateway}" ]]; then # Let the user know we will ping the gateway for a response - log_write " * Trying three pings on IPv${protocol} gateway at ${gateway}..." + log_write "* Trying three pings on IPv${protocol} gateway at ${gateway}..." # Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only, # on the pihole interface, and tail the last three lines of the output # If pinging the gateway is not successful, if ! ping_cmd="$(${cmd} -q -c 3 -W 3 -n ${gateway} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then # let the user know - log_write " ${CROSS} ${COL_LIGHT_RED}Gateway did not respond.${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}Gateway did not respond.${COL_NC}\n" # and return an error code return 1 # Otherwise, else # show a success - log_write " ${TICK} ${COL_LIGHT_GREEN}Gateway responded.${COL_NC}" + log_write "${TICK} ${COL_LIGHT_GREEN}Gateway responded.${COL_NC}\n" # and return a success code return 0 fi @@ -442,15 +444,15 @@ ping_internet() { # and Google's public IPv4 address local public_address="8.8.8.8" fi - echo -n " ${INFO} Trying three pings on IPv${protocol} to reach the Internet..." + echo -n "${INFO} Trying three pings on IPv${protocol} to reach the Internet..." # Try to ping the address 3 times if ! ping_inet="$(${cmd} -q -W 3 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then # if it's unsuccessful, show an error - log_write " ${CROSS} ${COL_LIGHT_RED}Cannot reach the Internet.${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}Cannot reach the Internet.${COL_NC}\n" return 1 else # Otherwise, show success - log_write " ${TICK} ${COL_LIGHT_GREEN}Query responded.${COL_NC}" + log_write "${TICK} ${COL_LIGHT_GREEN}Query responded.${COL_NC}\n" return 0 fi } @@ -458,7 +460,7 @@ ping_internet() { check_required_ports() { # Since Pi-hole needs 53, 80, and 4711, check what they are being used by # so we can detect any issues - log_write " ${INFO} Ports in use:" + log_write "${INFO} Ports in use:" # Create an array for these ports in use ports_in_use=() # Sort the addresses and remove duplicates @@ -475,35 +477,35 @@ check_required_ports() { case "${port_number}" in 53) if [[ "${service_name}" == "dnsmasq" ]]; then # if port 53 is dnsmasq, show it in green as it's standard - log_write " [${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" + log_write "[${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" # Otherwise, else # Show the service name in red since it's non-standard - log_write " [${COL_LIGHT_RED}${port_number}${COL_NC}] is in use by ${COL_LIGHT_RED}${service_name}${COL_NC} + log_write "[${COL_LIGHT_RED}${port_number}${COL_NC}] is in use by ${COL_LIGHT_RED}${service_name}${COL_NC} Please see: ${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC}" fi ;; 80) if [[ "${service_name}" == "lighttpd" ]]; then # if port 53 is dnsmasq, show it in green as it's standard - log_write " [${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" + log_write "[${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" # Otherwise, else # Show the service name in red since it's non-standard - log_write " [${COL_LIGHT_RED}${port_number}${COL_NC}] is in use by ${COL_LIGHT_RED}${service_name}${COL_NC} + log_write "[${COL_LIGHT_RED}${port_number}${COL_NC}] is in use by ${COL_LIGHT_RED}${service_name}${COL_NC} Please see: ${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC}" fi ;; 4711) if [[ "${service_name}" == "pihole-FT" ]]; then # if port 4711 is pihole-FTL, show it in green as it's standard - log_write " [${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" + log_write "[${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" # Otherwise, else # Show the service name in yellow since it's non-standard, but should still work - log_write " [${COL_YELLOW}${port_number}${COL_NC}] is in use by ${COL_YELLOW}${service_name}${COL_NC} + log_write "[${COL_YELLOW}${port_number}${COL_NC}] is in use by ${COL_YELLOW}${service_name}${COL_NC} Please see: ${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC}" fi ;; - *) log_write " [${port_number}] is in use by ${service_name}"; + *) log_write "[${port_number}] is in use by ${service_name}"; esac done } @@ -533,19 +535,19 @@ check_x_headers() { # If the X-header found by curl matches what is should be, if [[ $block_page == $block_page_working ]]; then # display a success message - log_write " $TICK ${COL_LIGHT_GREEN}${block_page}${COL_NC}" + log_write "$TICK ${COL_LIGHT_GREEN}${block_page}${COL_NC}" else # Otherwise, show an error - log_write " $CROSS ${COL_LIGHT_RED}X-Header does not match or could not be retrieved.${COL_NC}" + log_write "$CROSS ${COL_LIGHT_RED}X-Header does not match or could not be retrieved.${COL_NC}" fi # Same logic applies to the dashbord as above, if the X-Header matches what a working system shoud have, if [[ $dashboard == $dashboard_working ]]; then # then we can show a success - log_write " $TICK ${COL_LIGHT_GREEN}${dashboard}${COL_NC}" + log_write "$TICK ${COL_LIGHT_GREEN}${dashboard}${COL_NC}" else # Othewise, it's a failure since the X-Headers either don't exist or have been modified in some way - log_write " $CROSS ${COL_LIGHT_RED}X-Header does not match or could not be retrieved.${COL_NC}" + log_write "$CROSS ${COL_LIGHT_RED}X-Header does not match or could not be retrieved.${COL_NC}" fi } @@ -590,10 +592,10 @@ dig_at() { # First, do a dig on localhost to see if Pi-hole can use itself to block a domain if local_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then # If it can, show sucess - log_write " ${TICK} ${COL_LIGHT_GREEN}${random_url} is ${local_dig}${COL_NC} via localhost (${local_address})" + log_write "${TICK} ${random_url} ${COL_LIGHT_GREEN}is ${local_dig}${COL_NC} via localhost (${local_address})" else # Otherwise, show a failure - log_write " ${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} ${COL_LIGHT_RED}via localhost${COL_NC} (${local_address})" + log_write "${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} ${COL_LIGHT_RED}via localhost${COL_NC} (${local_address})" fi # Next we need to check if Pi-hole can resolve a domain when the query is sent to it's IP address @@ -604,20 +606,20 @@ dig_at() { # If Pi-hole can dig itself from it's IP (not the loopback address) if pihole_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then # show a success - log_write " ${TICK} ${COL_LIGHT_GREEN}${random_url} is ${pihole_dig}${COL_NC} via Pi-hole (${pihole_address})" + log_write "${TICK} ${random_url} ${COL_LIGHT_GREEN}is ${pihole_dig}${COL_NC} via Pi-hole (${pihole_address})" else # Othewise, show a failure - log_write " ${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} ${COL_LIGHT_RED}via Pi-hole${COL_NC} (${pihole_address})" + log_write "${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} ${COL_LIGHT_RED}via Pi-hole${COL_NC} (${pihole_address})" fi # Finally, we need to make sure legitimate queries can out to the Internet using an external, public DNS server # We are using the static remote_url here instead of a random one because we know it works with IPv4 and IPv6 if remote_dig=$(dig +tries=1 +time=2 -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then # If successful, the real IP of the domain will be returned instead of Pi-hole's IP - log_write " ${TICK} ${COL_LIGHT_GREEN}${remote_url} is ${remote_dig}${COL_NC} via a remote, public DNS server (${remote_address})" + log_write "${TICK} ${remote_url} ${COL_LIGHT_GREEN}is ${remote_dig}${COL_NC} via a remote, public DNS server (${remote_address})" else # Otherwise, show an error - log_write " ${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${remote_url} ${COL_LIGHT_RED}via a remote, public DNS server${COL_NC} (${remote_address})" + log_write "${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${remote_url} ${COL_LIGHT_RED}via a remote, public DNS server${COL_NC} (${remote_address})" fi } @@ -635,14 +637,25 @@ process_status(){ # and print it out to the user if [[ "${status_of_process}" == "active" ]]; then # If it's active, show it in green - log_write " ${TICK} ${COL_LIGHT_GREEN}${i}${COL_NC} daemon is ${COL_LIGHT_GREEN}${status_of_process}${COL_NC}" + log_write "${TICK} ${COL_LIGHT_GREEN}${i}${COL_NC} daemon is ${COL_LIGHT_GREEN}${status_of_process}${COL_NC}" else # If it's not, show it in red - log_write " ${CROSS} ${COL_LIGHT_RED}${i}${COL_NC} daemon is ${COL_LIGHT_RED}${status_of_process}${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}${i}${COL_NC} daemon is ${COL_LIGHT_RED}${status_of_process}${COL_NC}" fi done } +make_array_from_file() { + local filename="${1}" + if [[ -d "${filename}" ]]; then + : + else + while IFS= read -r line;do + file_content+=("${line}") + done < "${filename}" + fi +} + parse_file() { # Set the first argument passed to this function as a named variable for better readability local filename="${1}" @@ -655,8 +668,8 @@ parse_file() { local file_lines # For each line in the file, for file_lines in "${file_info[@]}"; do - # display the information with the ${INFO} icon - log_write " ${INFO} ${file_lines}" + # Display the file's content + log_write " ${file_lines}" | grep -v "#" | sed '/^$/d' done # Set the IFS back to what it was IFS="$OLD_IFS" @@ -668,7 +681,7 @@ diagnose_setup_variables() { # If the variable file exists, file_exists "${VARSFILE}" && \ - log_write " * Sourcing ${VARSFILE}..."; + log_write "* Sourcing ${VARSFILE}..."; # source it source ${VARSFILE}; # and display a green check mark with ${DONE} @@ -701,10 +714,10 @@ dir_check() { for filename in "${directory}"; do # check if exists first; if it does, file_exists "${filename}" && \ - # show a success message - echo_succes_or_fail "Files detected" || \ + # do nothing + : || \ # Otherwise, show an error - echo_succes_or_fail "${COL_LIGHT_RED}irectory does not exist.${COL_NC}" + echo_succes_or_fail "${COL_LIGHT_RED}directory does not exist.${COL_NC}" done } @@ -715,9 +728,19 @@ list_files_in_dir() { files_found=( $(ls "${dir_to_parse}") ) # For each file in the arry, for each_file in "${files_found[@]}"; do - # display the information with the ${INFO} icon - # Also print the permissions and the user/group - log_write " ${INFO} $(ls -ld ${dir_to_parse}/${each_file})" + if [[ -d "${each_file}" ]]; then + : + else + # display the information with the ${INFO} icon + # Also print the permissions and the user/group + log_write "\n${COL_LIGHT_GREEN}$(ls -ld ${dir_to_parse}/${each_file})${COL_NC}" + # Otherwise, parse the file's content + make_array_from_file "${dir_to_parse}/${each_file}" + for each_line in "${file_content[@]}"; do + log_write " ${each_line}" + done + fi + file_content=() done } @@ -761,10 +784,9 @@ analyze_gravity_list() { echo_current_diagnostic "Gravity list" # It's helpful to know how big a user's gravity file is gravity_length=$(grep -c ^ "${GRAVITYFILE}") && \ - log_write " ${INFO} ${GRAVITYFILE} is ${gravity_length} lines long."; - parse_file ${GRAVITYFILE} || \ + log_write "${INFO} ${GRAVITYFILE} is ${gravity_length} lines long." || \ # If the previous command failed, something is wrong with the file - log_write " ${CROSS} ${COL_LIGHT_RED}${GRAVITYFILE} not found!${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}${GRAVITYFILE} not found!${COL_NC}" } tricorder_use_nc_or_ssl() { @@ -772,13 +794,13 @@ tricorder_use_nc_or_ssl() { # Check for openssl first since encryption is a good thing if command -v openssl &> /dev/null; then # If the command exists, - log_write " * Using ${COL_LIGHT_GREEN}openssl${COL_NC} for transmission." + log_write " * Using ${COL_LIGHT_GREEN}openssl${COL_NC} for transmission." # encrypt and transmit the log and store the token returned in a variable tricorder_token=$(cat ${DEBUG_LOG} | openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null) # Otherwise, else # use net cat - log_write " ${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." + log_write "${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." tricorder_token=$(cat ${DEBUG_LOG} | nc tricorder.pi-hole.net 9999) fi } @@ -791,23 +813,22 @@ upload_to_tricorder() { # Let the user know debugging is complete echo "" - log_write "${TICK} Finished debugging!" + log_write "${TICK} ${COL_LIGHT_GREEN}** Finished debugging! **${COL_NC}\n" # Provide information on what they should do with their token - log_write " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." - log_write " * For more information, see: ${COL_CYAN}https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/${COL_NC}" - log_write "" - log_write " * If available, we'll use openssl to upload the log, otherwise it will fall back to netcat." + log_write " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." + log_write " * For more information, see: ${COL_CYAN}https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/${COL_NC}" + log_write " * If available, we'll use openssl to upload the log, otherwise it will fall back to netcat." # If pihole -d is running automatically (usually throught the dashboard) if [[ "${AUTOMATED}" ]]; then # let the user know - log_write " ${INFO} Debug script running in automated mode" + log_write "${INFO} Debug script running in automated mode" # and then decide again which tool to use to submit it if command -v openssl &> /dev/null; then - log_write " ${INFO} Using ${COL_LIGHT_GREEN}openssl${COL_NC} for transmission." + log_write "${INFO} Using ${COL_LIGHT_GREEN}openssl${COL_NC} for transmission." tricorder_token=$(openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin) else - log_write " ${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." + log_write "${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." tricorder_token=$(nc tricorder.pi-hole.net 9999 < /dev/stdin) fi else @@ -819,7 +840,7 @@ upload_to_tricorder() { # If they say yes, run our function for uploading the log [yY][eE][sS]|[yY]) tricorder_use_nc_or_ssl;; # If they choose no, just exit out of the script - *) log_write " * Log will ${COL_LIGHT_GREE}NOT${COL_NC} be uploaded to tricorder.";exit; + *) log_write " * Log will ${COL_LIGHT_GREEN}NOT${COL_NC} be uploaded to tricorder.";exit; esac fi # Check if tricorder.pi-hole.net is reachable and provide token @@ -829,19 +850,15 @@ upload_to_tricorder() { log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" log_write "${TICK} Your debug token is: ${COL_LIGHT_GREEN}${tricorder_token}${COL_NC}" log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" - log_write "" - log_write " Provide this token to the Pi-hole team for assistance:" - echo "" - log_write " https://discourse.pi-hole.net" - echo "" - log_write " Your log will self-destruct after 48 hours." + + log_write " * Provide this token to the Pi-hole team for assistance:" + log_write " * ${COL_CYAN}https://discourse.pi-hole.net${COL_NC}" + log_write " * Your log will self-destruct after ${COL_LIGHT_RED}48 hours${COL_NC}." else - log_write " ${CROSS} There was an error uploading your debug log." - log_write " Please try again or contact the Pi-hole team for assistance." + log_write "${CROSS} ${COL_LIGHT_RED}There was an error uploading your debug log.${COL_NC}" + log_write " * Please try again or contact the Pi-hole team for assistance." fi - echo "" - log_write " A local copy of the debug log can be found at : /var/log/pihole_debug.log" - echo "" + log_write " * A local copy of the debug log can be found at : ${COL_CYAN}${DEBUG_LOG}${COL_NC}\n" } # Run through all the functions we made From d9135347935d9150443e405b4d0ef92f64c03f63 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 27 May 2017 17:51:41 +0200 Subject: [PATCH 053/162] Move wildcards file if blocking is disabled (#1495) * Move wildcards file if blocking is diabled * Delete newline --- pihole | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pihole b/pihole index f89b67b2..1fb985e1 100755 --- a/pihole +++ b/pihole @@ -176,6 +176,9 @@ Time: elif [[ "${1}" == "0" ]]; then # Disable Pi-hole sed -i 's/^addn-hosts=\/etc\/pihole\/gravity.list/#addn-hosts=\/etc\/pihole\/gravity.list/' /etc/dnsmasq.d/01-pihole.conf + if [[ -e "$wildcardlist" ]]; then + mv "$wildcardlist" "/etc/pihole/wildcard.list" + fi echo "::: Blocking has been disabled!" if [[ $# > 1 ]]; then if [[ "${2}" == *"s"* ]]; then @@ -199,6 +202,9 @@ Time: # Enable Pi-hole echo "::: Blocking has been enabled!" sed -i 's/^#addn-hosts/addn-hosts/' /etc/dnsmasq.d/01-pihole.conf + if [[ -e "/etc/pihole/wildcard.list" ]]; then + mv "/etc/pihole/wildcard.list" "$wildcardlist" + fi fi restartDNS } @@ -305,7 +311,7 @@ tricorderFunc() { echo "Please do not call Tricorder directly." exit 1 fi - + if ! timeout 2 nc -z tricorder.pi-hole.net 9998 &> /dev/null; then echo "Unable to connect to Pi-hole's Tricorder server." exit 1 From d51e0c49b1009c2637d52deecd71a4314c32b2a4 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 27 May 2017 13:44:33 -0500 Subject: [PATCH 054/162] remove comments and blank lines when parsing files --- advanced/Scripts/piholeDebug.sh | 35 ++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 86ee4e23..dff5efeb 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -107,7 +107,7 @@ echo_current_diagnostic() { log_write "\n${COL_LIGHT_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}" } -file_exists() { +if_file_exists() { # Set the first argument passed to tihs function as a named variable for better readability local file_to_test="${1}" # If the file is readable @@ -338,7 +338,7 @@ diagnose_operating_system() { echo_current_diagnostic "Operating system" # If there is a /etc/*release file, it's probably a supported operating system, so we can - file_exists /etc/*release && \ + if_file_exists /etc/*release && \ # display the attributes to the user from the function made earlier get_distro_attributes || \ # If it doesn't exist, it's not a system we currently support and link to FAQ @@ -409,6 +409,7 @@ ping_gateway() { # If the gateway variable has a value (meaning a gateway was found), if [[ -n "${gateway}" ]]; then + log_write "${INFO} Default gateway: ${gateway}" # Let the user know we will ping the gateway for a response log_write "* Trying three pings on IPv${protocol} gateway at ${gateway}..." # Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only, @@ -647,11 +648,23 @@ process_status(){ make_array_from_file() { local filename="${1}" + # If the file is a directory if [[ -d "${filename}" ]]; then + # do nothing since it cannot be parsed : else + # Otherwise, read the file line by line while IFS= read -r line;do - file_content+=("${line}") + # Strip out comments and blank lines + new_line=$(echo "${line}" | sed -e 's/#.*$//' -e '/^$/d') + # If the line still has content + if [[ -n "${new_line}" ]]; then + # Put it into the array + file_content+=("${new_line}") + else + # Otherwise, it's a blank line or comment, so do nothing + : + fi done < "${filename}" fi } @@ -669,7 +682,7 @@ parse_file() { # For each line in the file, for file_lines in "${file_info[@]}"; do # Display the file's content - log_write " ${file_lines}" | grep -v "#" | sed '/^$/d' + log_write " ${file_lines}" done # Set the IFS back to what it was IFS="$OLD_IFS" @@ -680,7 +693,7 @@ diagnose_setup_variables() { echo_current_diagnostic "Setup variables" # If the variable file exists, - file_exists "${VARSFILE}" && \ + if_file_exists "${VARSFILE}" && \ log_write "* Sourcing ${VARSFILE}..."; # source it source ${VARSFILE}; @@ -713,7 +726,7 @@ dir_check() { # For each file in the directory, for filename in "${directory}"; do # check if exists first; if it does, - file_exists "${filename}" && \ + if_file_exists "${filename}" && \ # do nothing : || \ # Otherwise, show an error @@ -851,14 +864,14 @@ upload_to_tricorder() { log_write "${TICK} Your debug token is: ${COL_LIGHT_GREEN}${tricorder_token}${COL_NC}" log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" - log_write " * Provide this token to the Pi-hole team for assistance:" - log_write " * ${COL_CYAN}https://discourse.pi-hole.net${COL_NC}" - log_write " * Your log will self-destruct after ${COL_LIGHT_RED}48 hours${COL_NC}." + log_write " * Provide this token to the Pi-hole team for assistance:" + log_write " * ${COL_CYAN}https://discourse.pi-hole.net${COL_NC}" + log_write " * Your log will self-destruct after ${COL_LIGHT_RED}48 hours${COL_NC}." else log_write "${CROSS} ${COL_LIGHT_RED}There was an error uploading your debug log.${COL_NC}" - log_write " * Please try again or contact the Pi-hole team for assistance." + log_write " * Please try again or contact the Pi-hole team for assistance." fi - log_write " * A local copy of the debug log can be found at : ${COL_CYAN}${DEBUG_LOG}${COL_NC}\n" + log_write " * A local copy of the debug log can be found at : ${COL_CYAN}${DEBUG_LOG}${COL_NC}\n" } # Run through all the functions we made From 2b8a8b03a82c942c54cf1d9d7605cfe065e1f149 Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Sun, 28 May 2017 06:42:44 +1000 Subject: [PATCH 055/162] Roll back merge #1417 (#1494) --- pihole | 81 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/pihole b/pihole index 1fb985e1..08e6b094 100755 --- a/pihole +++ b/pihole @@ -80,49 +80,66 @@ updateGravityFunc() { exit 0 } -scanList() { +scanList(){ domain="${1}" list="${2}" method="${3}" - - if [[ "${method}" == "-exact" ]]; then - grep -i -E -l "(^|\s|\/)${domain}($|\s|\/)" ${list} + if [[ ${method} == "-exact" ]] ; then + grep -i -E "(^|\s)${domain}($|\s)" "${list}" else - grep -i "${domain}" ${list} + grep -i "${domain}" "${list}" fi } +processWildcards() { + IFS="." read -r -a array <<< "${1}" + for (( i=${#array[@]}-1; i>=0; i-- )); do + ar="" + for (( j=${#array[@]}-1; j>${#array[@]}-i-2; j-- )); do + if [[ $j == $((${#array[@]}-1)) ]]; then + ar="${array[$j]}" + else + ar="${array[$j]}.${ar}" + fi + done + echo "${ar}" + done +} + queryFunc() { + domain="${2}" method="${3}" + lists=( /etc/pihole/list.* /etc/pihole/blacklist.txt) + for list in ${lists[@]}; do + if [ -e "${list}" ]; then + result=$(scanList ${domain} ${list} ${method}) + # Remove empty lines before couting number of results + count=$(sed '/^\s*$/d' <<< "$result" | wc -l) + echo "::: ${list} (${count} results)" + if [[ ${count} > 0 ]]; then + echo "${result}" + fi + echo "" + else + echo "::: ${list} does not exist" + echo "" + fi + done - # If domain contains non ASCII characters, convert domain to punycode if python exists - # Cr: https://serverfault.com/a/335079 - if [[ -z "${2}" ]]; then - echo "::: No domain specified" - exit 1 - elif [[ "${2}" = *[![:ascii:]]* ]]; then - [[ "$(which python)" ]] && domain=$(python -c 'import sys;print sys.argv[1].decode("utf-8").encode("idna")' "${2}") - else - domain="${2}" + # Scan for possible wildcard matches + if [ -e "${wildcardlist}" ]; then + local wildcards=($(processWildcards "${domain}")) + for domain in ${wildcards[@]}; do + result=$(scanList "\/${domain}\/" ${wildcardlist}) + # Remove empty lines before couting number of results + count=$(sed '/^\s*$/d' <<< "$result" | wc -l) + if [[ ${count} > 0 ]]; then + echo "::: Wildcard blocking ${domain} (${count} results)" + echo "${result}" + echo "" + fi + done fi - - # Scan Whitelist, Blacklist and Wildcards - lists="/etc/pihole/whitelist.txt /etc/pihole/blacklist.txt $wildcardlist" - result=$(scanList ${domain} "${lists}" ${method}) - if [[ -n "$result" ]]; then - echo "$result" - [[ ! -t 1 ]] && exit 0 - fi - - # Scan Domains lists - result=$(scanList ${domain} "/etc/pihole/*.domains" ${method}) - if [[ -n "$result" ]]; then - sort -t . -k 2 -g <<< "$result" - else - [ -n "$method" ] && exact="exact " - echo "::: No ${exact}results found for ${domain}" - fi - exit 0 } From 2fea5d428d95030ad22393e9f8fc1d9653136375 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 27 May 2017 15:47:15 -0500 Subject: [PATCH 056/162] condense repetitive code into functions --- advanced/Scripts/piholeDebug.sh | 183 ++++++++++++-------------------- 1 file changed, 66 insertions(+), 117 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index dff5efeb..3c04d909 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +check_critical_program_versions#!/usr/bin/env bash # Pi-hole: A black hole for Internet advertisements # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. @@ -133,48 +133,57 @@ if_directory_exists() { fi } -# Checks the core version of the Pi-hole codebase -check_core_version() { - echo_current_diagnostic "Pi-hole versions" +compare_local_version_to_git_version() { + # The git directory to check + local git_dir="${1}" + # The named component of the project (Core or Web) + local pihole_component="${2}" + # If we are checking the Core versions, + if [[ "${pihole_component}" == "Core" ]]; then + # We need to search for "Pi-hole" when using pihole -v + local search_term="Pi-hole" + elif [[ "${pihole_component}" == "Web" ]]; then + local search_term="AdminLTE" + fi + # Display what we are checking + echo_current_diagnostic "${pihole_component} version" # Store the error message in a variable in case we want to change and/or reuse it local error_msg="git status failed" # If the pihole git directory exists, - if_directory_exists "${PIHOLEGITDIR}" && \ + if_directory_exists "${git_dir}" && \ # move into it - cd "${PIHOLEGITDIR}" || \ - # if not, report an error - log_write "pihole repo does not exist" - # If the git status command completes successfully, - # we can assume we can get the information we want + cd "${git_dir}" || \ + # If not, show an error + log_write "${COL_LIGHT_RED}Could not cd into ${git_dir}$COL_NC" if git status &> /dev/null; then # The current version the user is on - PI_HOLE_VERSION=$(git describe --tags --abbrev=0); + local remote_version=$(git describe --tags --abbrev=0); # What branch they are on - PI_HOLE_BRANCH=$(git rev-parse --abbrev-ref HEAD); + local remote_branch=$(git rev-parse --abbrev-ref HEAD); # The commit they are on - PI_HOLE_COMMIT=$(git describe --long --dirty --tags --always) + local remote_commit=$(git describe --long --dirty --tags --always) # echo this information out to the user in a nice format # If the current version matches what pihole -v produces, the user is up-to-date - if [[ "${PI_HOLE_VERSION}" == "$(pihole -v | awk '/Pi-hole/ {print $6}' | cut -d ')' -f1)" ]]; then - log_write "${TICK} Core: ${COL_LIGHT_GREEN}${PI_HOLE_VERSION}${COL_NC}" + if [[ "${remote_version}" == "$(pihole -v | awk '/${search_term}/ {print $6}' | cut -d ')' -f1)" ]]; then + log_write "${TICK} ${pihole_component}: ${COL_LIGHT_GREEN}${remote_version}${COL_NC}" # If not, else # echo the current version in yellow, signifying it's something to take a look at, but not a critical error # Also add a URL to an FAQ - log_write "${INFO} Core: ${COL_YELLOW}${PI_HOLE_VERSION:-Untagged}${COL_NC} (${COL_CYAN}${FAQ_UPDATE_PI_HOLE}${COL_NC})" + log_write "${INFO} ${pihole_component}: ${COL_YELLOW}${remote_version:-Untagged}${COL_NC} (${COL_CYAN}${FAQ_UPDATE_PI_HOLE}${COL_NC})" fi # If the repo is on the master branch, they are on the stable codebase - if [[ "${PI_HOLE_BRANCH}" == "master" ]]; then + if [[ "${remote_branch}" == "master" ]]; then # so the color of the text is green - log_write "${INFO} Branch: ${COL_LIGHT_GREEN}${PI_HOLE_BRANCH}${COL_NC}" + log_write "${INFO} Branch: ${COL_LIGHT_GREEN}${remote_branch}${COL_NC}" # If it is any other branch, they are in a developement branch else # So show that in yellow, signifying it's something to take a look at, but not a critical error - log_write "${INFO} Branch: ${COL_YELLOW}${PI_HOLE_BRANCH:-Detached}${COL_NC} (${COL_CYAN}${FAQ_CHECKOUT_COMMAND}${COL_NC})" + log_write "${INFO} Branch: ${COL_YELLOW}${remote_branch:-Detached}${COL_NC} (${COL_CYAN}${FAQ_CHECKOUT_COMMAND}${COL_NC})" fi # echo the current commit - log_write "${INFO} Commit: ${PI_HOLE_COMMIT}\n" + log_write "${INFO} Commit: ${remote_commit}" # If git status failed, else # Return an error message @@ -182,123 +191,65 @@ check_core_version() { # and exit with a non zero code return 1 fi -} -check_web_version() { - # Local variable for the error message - local error_msg="git status failed" - # If the directory exists, - if_directory_exists "${ADMINGITDIR}" && \ - # move into it - cd "${ADMINGITDIR}" || \ - # if not, give an error message - log_write "repo does not exist" - # If the git status command completes successfully, - # we can assume we can get the information we want - if git status &> /dev/null; then - # The current version the user is on - WEB_VERSION=$(git describe --tags --abbrev=0); - # What branch they are on - WEB_BRANCH=$(git rev-parse --abbrev-ref HEAD); - # The commit they are on - WEB_COMMIT=$(git describe --long --dirty --tags --always) - # If the Web version reported by pihole -v matches the current version - if [[ "${WEB_VERSION}" == "$(pihole -v | awk '/AdminLTE/ {print $6}' | cut -d ')' -f1)" ]]; then - # echo it in green - log_write "${TICK} Web: ${COL_LIGHT_GREEN}${WEB_VERSION}${COL_NC}" - # Otherwise, - else - # Show it in yellow with a link to update Pi-hole - log_write "${INFO} Web: ${COL_YELLOW}${WEB_VERSION:-Untagged}${COL_NC} (${COL_CYAN}${FAQ_UPDATE_PI_HOLE}${COL_NC})" - fi - - - # If the repo is on the master branch, they are on the stable codebase - if [[ "${WEB_BRANCH}" == "master" ]]; then - # so the color of the text is green - log_write "${TICK} Branch: ${COL_LIGHT_GREEN}${WEB_BRANCH}${COL_NC}" - else - # If it is any other branch, they are in a developement branch - # So show that in yellow, signifying it's something to take a look at, but not a critical error - log_write "${INFO} Branch: ${COL_YELLOW}${WEB_BRANCH:-Detached}${COL_NC} (${COL_CYAN}${FAQ_CHECKOUT_COMMAND}${COL_NC})" - fi - # echo the current commit - log_write "${INFO} Commit: ${WEB_COMMIT}\n" - # If git status failed, - else - # Return an error message - log_write "${error_msg}" - # and exit with a non zero code - return 1 - fi } check_ftl_version() { + local ftl_name="FTL" + echo_current_diagnostic "${ftl_name} version" # Use the built in command to check FTL's version FTL_VERSION=$(pihole-FTL version) # Compare the current FTL version to the remote version if [[ "${FTL_VERSION}" == "$(pihole -v | awk '/FTL/ {print $6}' | cut -d ')' -f1)" ]]; then # If they are the same, FTL is up-to-date - log_write "${TICK} FTL: ${COL_LIGHT_GREEN}${FTL_VERSION}${COL_NC}" + log_write "${TICK} ${ftl_name}: ${COL_LIGHT_GREEN}${FTL_VERSION}${COL_NC}" else # If not, show it in yellow, signifying there is an update - log_write "${TICK} FTL: ${COL_YELLOW}${FTL_VERSION}${COL_NC}" + log_write "${TICK} ${ftl_name}: ${COL_YELLOW}${FTL_VERSION}${COL_NC}" fi } -# Check the current version of the Web server -check_web_server_version() { - # Store the name in a variable in case we ever want to change it - WEB_SERVER="lighttpd" - # Parse out just the version number - WEB_SERVER_VERSON="$(lighttpd -v |& head -n1 | cut -d '/' -f2 | cut -d ' ' -f1)" +# Checks the core version of the Pi-hole codebase +check_component_versions() { + # Check the Web version, branch, and commit + compare_local_version_to_git_version "${PIHOLEGITDIR}" "Core" + # Check the Web version, branch, and commit + compare_local_version_to_git_version "${ADMINGITDIR}" "Web" + # Check the FTL version + check_ftl_version +} + + +get_program_version() { + local program_name="${1}" + local program_version + echo_current_diagnostic "${program_name} version" + case "${program_name}" in + "lighttpd") program_version="$(${program_name} -v |& head -n1 | cut -d '/' -f2 | cut -d ' ' -f1)" + ;; + "dnsmasq") program_version="$(${program_name} -v |& head -n1 | awk '{print $3}')" + ;; + "php") program_version="$(${program_name} -v |& head -n1 | cut -d '-' -f1 | cut -d ' ' -f2)" + ;; + *) echo "Unrecognized program"; + esac # If the Web server does not have a version (the variable is empty) - if [[ -z "${WEB_SERVER_VERSON}" ]]; then + if [[ -z "${program_version}" ]]; then # Display and error - log_write "${CROSS} ${COL_LIGHT_RED}${WEB_SERVER} version could not be detected.${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}${program_name} version could not be detected.${COL_NC}" else # Otherwise, display the version - log_write "${TICK} ${WEB_SERVER}: ${WEB_SERVER_VERSON}" - fi -} - -# Check the current version of the DNS server -check_resolver_server_version() { - # Store the name in a variable in case we ever want to change it - RESOLVER="dnsmasq" - # Parse out just the version number - RESOVLER_VERSON="$(dnsmasq -v |& head -n1 | awk '{print $3}')" - # If the DNS server does not have a version (the variable is empty) - if [[ -z "${RESOVLER_VERSON}" ]]; then - # Display and error - log_write "${CROSS} ${COL_LIGHT_RED}${RESOLVER} version could not be detected.${COL_NC}" - else - # Otherwise, display the version - log_write "${TICK} ${RESOLVER}: ${RESOVLER_VERSON}" - fi -} - -check_php_version() { - # Parse out just the version number - PHP_VERSION=$(php -v |& head -n1 | cut -d '-' -f1 | cut -d ' ' -f2) - # If no version is detected, - if [[ -z "${PHP_VERSION}" ]]; then - # show an error - log_write "${CROSS} ${COL_LIGHT_RED}PHP version could not be detected.${COL_NC}" - else - # Otherwise, show the version - log_write "${TICK} PHP: ${PHP_VERSION}" + log_write "${TICK} ${program_name}: ${program_version}" fi } # These are the most critical dependencies of Pi-hole, so we check for them # and their versions, using the functions above. -check_critical_dependencies() { - echo_current_diagnostic "Versions of critical dependencies" +check_critical_program_versions() { # Use the function created earlier and bundle them into one function that checks all the version numbers - check_web_server_version - check_resolver_server_version - check_php_version + get_program_version "dnsmasq" + get_program_version "lighttpd" + get_program_version "php" } get_distro_attributes() { @@ -877,9 +828,8 @@ upload_to_tricorder() { # Run through all the functions we made make_temporary_log initiate_debug -check_core_version -check_web_version -check_ftl_version +check_component_versions +check_critical_program_versions # setupVars.conf needs to be sourced before the networking so the values are # available to the check_networking function diagnose_setup_variables @@ -889,7 +839,6 @@ check_networking check_name_resolution process_status check_x_headers -check_critical_dependencies analyze_gravity_list check_dnsmasq_d check_lighttpd_d From d51c067e1bddfc8d5d3b9264b72275cb064c8b8d Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 27 May 2017 21:21:18 -0500 Subject: [PATCH 057/162] change some verbiage; new function to compare the ports in use to the services assigned to them. --- advanced/Scripts/piholeDebug.sh | 117 ++++++++++++++++---------------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 3c04d909..8fe1d346 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -55,6 +55,18 @@ else OVER="\r\033[K" fi +source_setup_variables() { + # Display the current test that is running + log_write "\n${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC} Sourcing setup varibles" + # If the variable file exists, + if_file_exists "${VARSFILE}" && \ + log_write "${INFO} Sourcing ${VARSFILE}..."; + # source it + source ${VARSFILE} || \ + # If it can't, show an error + log_write "${VARSFILE} ${COL_LIGHT_RED}does not exist or cannot be read.${COL_NC}" +} + make_temporary_log() { # Create temporary file for log TEMPLOG=$(mktemp /tmp/pihole_temp.XXXXXX) @@ -205,7 +217,7 @@ check_ftl_version() { log_write "${TICK} ${ftl_name}: ${COL_LIGHT_GREEN}${FTL_VERSION}${COL_NC}" else # If not, show it in yellow, signifying there is an update - log_write "${TICK} ${ftl_name}: ${COL_YELLOW}${FTL_VERSION}${COL_NC}" + log_write "${TICK} ${ftl_name}: ${COL_YELLOW}${FTL_VERSION}${COL_NC} ${FAQ_UPDATE_PI_HOLE}" fi } @@ -310,6 +322,13 @@ processor_check() { fi } +parse_setup_vars() { + echo_current_diagnostic "Setup variables" + if_file_exists "${VARSFILE}" && \ + parse_file "${VARSFILE}" || \ + log_write "${CROSS} ${COL_LIGHT_RED}Could not read ${VARSFILE}.${COL_NC}" +} + detect_ip_addresses() { # First argument should be a 4 or a 6 local protocol=${1} @@ -323,16 +342,16 @@ detect_ip_addresses() { # Local iterator local i # Display the protocol and interface - log_write "${TICK} IPv${protocol} on ${PIHOLE_INTERFACE}" + log_write "${TICK} IPv${protocol} address(es) bound to the ${PIHOLE_INTERFACE} interface:" # Since there may be more than one IP address, store them in an array for i in "${!ip_addr_list[@]}"; do # For each one in the list, print it out - log_write "${ip_addr_list[$i]}" + log_write " ${ip_addr_list[$i]}" done log_write "" else # If there are no IPs detected, explain that the protocol is not configured - log_write "${CROSS} ${COL_LIGHT_RED}No IPv${protocol} found on ${PIHOLE_INTERFACE}${COL_NC}\n" + log_write "${CROSS} ${COL_LIGHT_RED}No IPv${protocol} address(es) found on the ${PIHOLE_INTERFACE}${COL_NC} interace.\n" return 1 fi } @@ -360,21 +379,21 @@ ping_gateway() { # If the gateway variable has a value (meaning a gateway was found), if [[ -n "${gateway}" ]]; then - log_write "${INFO} Default gateway: ${gateway}" + log_write "${INFO} Default IPv${protocol} gateway: ${gateway}" # Let the user know we will ping the gateway for a response - log_write "* Trying three pings on IPv${protocol} gateway at ${gateway}..." + log_write "* Pinging IPv${protocol} gateway..." # Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only, # on the pihole interface, and tail the last three lines of the output # If pinging the gateway is not successful, - if ! ping_cmd="$(${cmd} -q -c 3 -W 3 -n ${gateway} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then + if ! ${cmd} -c 3 -W 3 -n ${gateway} -I ${PIHOLE_INTERFACE} | tail -n 3; then # let the user know - log_write "${CROSS} ${COL_LIGHT_RED}Gateway did not respond.${COL_NC}\n" + log_write "${CROSS} ${COL_LIGHT_RED}Gateway did not respond.${COL_NC}" # and return an error code return 1 # Otherwise, else # show a success - log_write "${TICK} ${COL_LIGHT_GREEN}Gateway responded.${COL_NC}\n" + log_write "${TICK} ${COL_LIGHT_GREEN}Gateway responded.${COL_NC}" # and return a success code return 0 fi @@ -396,9 +415,9 @@ ping_internet() { # and Google's public IPv4 address local public_address="8.8.8.8" fi - echo -n "${INFO} Trying three pings on IPv${protocol} to reach the Internet..." + log_write "* Checking Internet connectivity via IPv${protocol}..." # Try to ping the address 3 times - if ! ping_inet="$(${cmd} -q -W 3 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then + if ! ping_inet="$(${cmd} -W 3 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then # if it's unsuccessful, show an error log_write "${CROSS} ${COL_LIGHT_RED}Cannot reach the Internet.${COL_NC}\n" return 1 @@ -409,10 +428,28 @@ ping_internet() { fi } +compare_port_to_service_assigned() { + local service_name="${1}" + local resolver="dnsmasq" + local web_server="lighttpd" + local ftl="pihole-FT" + if [[ "${service_name}" == "${resolver}" ]] || [[ "${service_name}" == "${web_server}" ]] || [[ "${service_name}" == "${ftl}" ]]; then + # if port 53 is dnsmasq, show it in green as it's standard + log_write "[${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" + # Otherwise, + else + # Show the service name in red since it's non-standard + log_write "[${COL_LIGHT_RED}${port_number}${COL_NC}] is in use by ${COL_LIGHT_RED}${service_name}${COL_NC} (${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC})" + fi +} + check_required_ports() { + echo_current_diagnostic "Ports in use" # Since Pi-hole needs 53, 80, and 4711, check what they are being used by # so we can detect any issues - log_write "${INFO} Ports in use:" + local resolver="dnsmasq" + local web_server="lighttpd" + local ftl="pihole-FT" # Create an array for these ports in use ports_in_use=() # Sort the addresses and remove duplicates @@ -427,35 +464,11 @@ check_required_ports() { local service_name=$(echo "${ports_in_use[$i]}" | awk '{print $2}') # Use a case statement to determine if the right services are using the right ports case "${port_number}" in - 53) if [[ "${service_name}" == "dnsmasq" ]]; then - # if port 53 is dnsmasq, show it in green as it's standard - log_write "[${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" - # Otherwise, - else - # Show the service name in red since it's non-standard - log_write "[${COL_LIGHT_RED}${port_number}${COL_NC}] is in use by ${COL_LIGHT_RED}${service_name}${COL_NC} - Please see: ${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC}" - fi + 53) compare_port_to_service_assigned "${resolver}" ;; - 80) if [[ "${service_name}" == "lighttpd" ]]; then - # if port 53 is dnsmasq, show it in green as it's standard - log_write "[${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" - # Otherwise, - else - # Show the service name in red since it's non-standard - log_write "[${COL_LIGHT_RED}${port_number}${COL_NC}] is in use by ${COL_LIGHT_RED}${service_name}${COL_NC} - Please see: ${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC}" - fi + 80) compare_port_to_service_assigned "${web_server}" ;; - 4711) if [[ "${service_name}" == "pihole-FT" ]]; then - # if port 4711 is pihole-FTL, show it in green as it's standard - log_write "[${COL_LIGHT_GREEN}${port_number}${COL_NC}] is in use by ${COL_LIGHT_GREEN}${service_name}${COL_NC}" - # Otherwise, - else - # Show the service name in yellow since it's non-standard, but should still work - log_write "[${COL_YELLOW}${port_number}${COL_NC}] is in use by ${COL_YELLOW}${service_name}${COL_NC} - Please see: ${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC}" - fi + 4711) compare_port_to_service_assigned "${ftl}" ;; *) log_write "[${port_number}] is in use by ${service_name}"; esac @@ -467,8 +480,8 @@ check_networking() { # together since they are all related to the networking aspect of things echo_current_diagnostic "Networking" detect_ip_addresses "4" - ping_gateway "4" detect_ip_addresses "6" + ping_gateway "4" ping_gateway "6" check_required_ports } @@ -639,23 +652,6 @@ parse_file() { IFS="$OLD_IFS" } -diagnose_setup_variables() { - # Display the current test that is running - echo_current_diagnostic "Setup variables" - - # If the variable file exists, - if_file_exists "${VARSFILE}" && \ - log_write "* Sourcing ${VARSFILE}..."; - # source it - source ${VARSFILE}; - # and display a green check mark with ${DONE} - echo_succes_or_fail "${COL_LIGHT_GREEN}${VARSFILE}${COL_NC} is readable and ${COL_LIGHT_GREEN}has been sourced.${COL_NC}" || \ - # Othwerwise, error out - echo_succes_or_fail "${VARSFILE} ${COL_LIGHT_RED}is not readable.${COL_NC} - ${INFO} $(ls -l ${VARSFILE} 2>/dev/null)"; - parse_file "${VARSFILE}" -} - check_name_resolution() { # Check name resoltion from localhost, Pi-hole's IP, and Google's name severs # using the function we created earlier @@ -827,17 +823,18 @@ upload_to_tricorder() { # Run through all the functions we made make_temporary_log +# setupVars.conf needs to be sourced before the networking so the values are +# available to the other functions initiate_debug +source_setup_variables check_component_versions check_critical_program_versions -# setupVars.conf needs to be sourced before the networking so the values are -# available to the check_networking function -diagnose_setup_variables diagnose_operating_system processor_check check_networking check_name_resolution process_status +parse_setup_vars check_x_headers analyze_gravity_list check_dnsmasq_d From 570c54002f3dfb212dff57a3708e83b1b27a4252 Mon Sep 17 00:00:00 2001 From: Dan Schaper Date: Tue, 30 May 2017 23:51:22 -0700 Subject: [PATCH 058/162] Update ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 3014625b..066b3f8f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -9,7 +9,7 @@ _{replace this text with a number from 1 to 10, with 1 being not familiar, and 10 being very familiar}_ --- -**[FEATURE REQUEST | QUESTION | OTHER]:** +**[BUG REPORT | QUESTION | OTHER]:** Please [submit your feature request here](https://discourse.pi-hole.net/c/feature-requests), so it is votable by the community. It's also easier for us to track. From 3a58e9d33abf843e42c44d1bfda69339b468450b Mon Sep 17 00:00:00 2001 From: Dan Schaper Date: Wed, 31 May 2017 00:02:57 -0700 Subject: [PATCH 059/162] Remove Question option --- .github/ISSUE_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 066b3f8f..23e67795 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -9,7 +9,7 @@ _{replace this text with a number from 1 to 10, with 1 being not familiar, and 10 being very familiar}_ --- -**[BUG REPORT | QUESTION | OTHER]:** +**[BUG REPORT | OTHER]:** Please [submit your feature request here](https://discourse.pi-hole.net/c/feature-requests), so it is votable by the community. It's also easier for us to track. From b207fadc04f16422d00a9b0bf9c03567f1ef5fcd Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Thu, 1 Jun 2017 00:18:06 -0500 Subject: [PATCH 060/162] check if os is supported based on pretty name --- advanced/Scripts/piholeDebug.sh | 37 ++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 8fe1d346..d5e2c9d7 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -19,6 +19,8 @@ set -o pipefail #IFS=$'\n\t' ######## GLOBAL VARS ######## +SUPPORTED_OS=("Raspbian" "Ubduntu" "Fedora" "Debian" "CentOS") + VARSFILE="/etc/pihole/setupVars.conf" DEBUG_LOG="/var/log/pihole_debug.log" DNSMASQFILE="/etc/dnsmasq.conf" @@ -37,8 +39,9 @@ readonly FTLLOG="/var/log/pihole-FTL.log" coltable=/opt/pihole/COL_TABLE # FAQ URLs -FAQ_UPDATE_PI_HOLE="https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249" -FAQ_CHECKOUT_COMMAND="https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout" +FAQ_UPDATE_PI_HOLE="${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC}" +FAQ_CHECKOUT_COMMAND="${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC}" +FAQ_HARDWARE_REQUIREMENTS="${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273${COL_NC}" # These provide the colors we need for making the log more readable if [[ -f ${coltable} ]]; then @@ -182,7 +185,7 @@ compare_local_version_to_git_version() { else # echo the current version in yellow, signifying it's something to take a look at, but not a critical error # Also add a URL to an FAQ - log_write "${INFO} ${pihole_component}: ${COL_YELLOW}${remote_version:-Untagged}${COL_NC} (${COL_CYAN}${FAQ_UPDATE_PI_HOLE}${COL_NC})" + log_write "${INFO} ${pihole_component}: ${COL_YELLOW}${remote_version:-Untagged}${COL_NC} (${FAQ_UPDATE_PI_HOLE})" fi # If the repo is on the master branch, they are on the stable codebase @@ -192,7 +195,7 @@ compare_local_version_to_git_version() { # If it is any other branch, they are in a developement branch else # So show that in yellow, signifying it's something to take a look at, but not a critical error - log_write "${INFO} Branch: ${COL_YELLOW}${remote_branch:-Detached}${COL_NC} (${COL_CYAN}${FAQ_CHECKOUT_COMMAND}${COL_NC})" + log_write "${INFO} Branch: ${COL_YELLOW}${remote_branch:-Detached}${COL_NC} (${FAQ_CHECKOUT_COMMAND})" fi # echo the current commit log_write "${INFO} Commit: ${remote_commit}" @@ -203,7 +206,6 @@ compare_local_version_to_git_version() { # and exit with a non zero code return 1 fi - } check_ftl_version() { @@ -217,7 +219,7 @@ check_ftl_version() { log_write "${TICK} ${ftl_name}: ${COL_LIGHT_GREEN}${FTL_VERSION}${COL_NC}" else # If not, show it in yellow, signifying there is an update - log_write "${TICK} ${ftl_name}: ${COL_YELLOW}${FTL_VERSION}${COL_NC} ${FAQ_UPDATE_PI_HOLE}" + log_write "${TICK} ${ftl_name}: ${COL_YELLOW}${FTL_VERSION}${COL_NC} (${FAQ_UPDATE_PI_HOLE})" fi } @@ -264,6 +266,19 @@ check_critical_program_versions() { get_program_version "php" } +is_os_supported() { + local os_to_check="${1}" + the_os=$(echo ${os_to_check} | sed 's/ .*//') + case "${the_os}" in + "Raspbian") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; + "Ubsuntu") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; + "Fedora") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; + "Debian") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; + "CentOS") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; + *) log_write "${CROSS} ${COL_LIGHT_RED}${os_to_check}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS})"; + esac +} + get_distro_attributes() { # Put the current Internal Field Separator into another variable so it can be restored later OLD_IFS="$IFS" @@ -279,10 +294,10 @@ get_distro_attributes() { local pretty_name_key=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f1) # we need just the OS PRETTY_NAME, if [[ "${pretty_name_key}" == "PRETTY_NAME" ]]; then - # so print it when we find it + # so save in in a variable when we find it PRETTY_NAME_VALUE=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f2- | tr -d '"') - # and then echoed out to the screen - log_write "${INFO} ${PRETTY_NAME_VALUE}" + # then pass it as an argument that checks if the OS is supported + is_os_supported "${PRETTY_NAME_VALUE}" else # Since we only need the pretty name, we can just skip over anything that is not a match : @@ -293,8 +308,6 @@ get_distro_attributes() { } diagnose_operating_system() { - # local variable for system requirements - FAQ_HARDWARE_REQUIREMENTS="https://discourse.pi-hole.net/t/hardware-software-requirements/273" # error message in a variable so we can easily modify it later (or re-use it) local error_msg="Distribution unknown -- most likely you are on an unsupported platform and may run into issues." # Display the current test that is running @@ -305,7 +318,7 @@ diagnose_operating_system() { # display the attributes to the user from the function made earlier get_distro_attributes || \ # If it doesn't exist, it's not a system we currently support and link to FAQ - log_write "${CROSS} ${COL_LIGHT_RED}${error_msg}${COL_NC} (${COL_CYAN}${FAQ_HARDWARE_REQUIREMENTS}${COL_NC})" + log_write "${CROSS} ${COL_LIGHT_RED}${error_msg}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS})" } processor_check() { From 02a601deff7f46f470b533a88915b766dc939e27 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Thu, 1 Jun 2017 00:19:15 -0500 Subject: [PATCH 061/162] comment out dir checks for lighttpd, cronm and http as they have a lot of other files that need parsing through. May need to increase the logic there if this is information we really need to know. --- advanced/Scripts/piholeDebug.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index d5e2c9d7..15576223 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -851,8 +851,8 @@ parse_setup_vars check_x_headers analyze_gravity_list check_dnsmasq_d -check_lighttpd_d -check_http_directory -check_cron_d +# check_lighttpd_d +# check_http_directory +# check_cron_d copy_to_debug_log upload_to_tricorder From 8b4c0b456b672713bfa138af7bb79b8df283e89d Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Thu, 1 Jun 2017 01:15:11 -0500 Subject: [PATCH 062/162] exclude webpassword from being uploaded. also check that the IP addresses detected match those defined in setupVars.conf --- advanced/Scripts/piholeDebug.sh | 111 +++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 15576223..954c6c31 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -19,7 +19,7 @@ set -o pipefail #IFS=$'\n\t' ######## GLOBAL VARS ######## -SUPPORTED_OS=("Raspbian" "Ubduntu" "Fedora" "Debian" "CentOS") +SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS") VARSFILE="/etc/pihole/setupVars.conf" DEBUG_LOG="/var/log/pihole_debug.log" @@ -38,11 +38,6 @@ WHITELISTMATCHES="/tmp/whitelistmatches.list" readonly FTLLOG="/var/log/pihole-FTL.log" coltable=/opt/pihole/COL_TABLE -# FAQ URLs -FAQ_UPDATE_PI_HOLE="${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC}" -FAQ_CHECKOUT_COMMAND="${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC}" -FAQ_HARDWARE_REQUIREMENTS="${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273${COL_NC}" - # These provide the colors we need for making the log more readable if [[ -f ${coltable} ]]; then source ${coltable} @@ -58,6 +53,13 @@ else OVER="\r\033[K" fi +# FAQ URLs +FAQ_UPDATE_PI_HOLE="${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC}" +FAQ_CHECKOUT_COMMAND="${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC}" +FAQ_HARDWARE_REQUIREMENTS="${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273${COL_NC}" +FAQ_GATEWAY="${COL_CYAN}https://discourse.pi-hole.net/{PLACEHOLDER}${COL_NC}" +FAQ_ULA="${COL_CYAN}https://discourse.pi-hole.net/t/use-ipv6-ula-addresses-for-pi-hole/2127${COL_NC}" + source_setup_variables() { # Display the current test that is running log_write "\n${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC} Sourcing setup varibles" @@ -271,7 +273,7 @@ is_os_supported() { the_os=$(echo ${os_to_check} | sed 's/ .*//') case "${the_os}" in "Raspbian") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; - "Ubsuntu") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; + "Ubuntu") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; "Fedora") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; "Debian") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; "CentOS") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; @@ -342,6 +344,37 @@ parse_setup_vars() { log_write "${CROSS} ${COL_LIGHT_RED}Could not read ${VARSFILE}.${COL_NC}" } +does_ip_match_setup_vars() { + # Check for IPv4 or 6 + local protocol="${1}" + # IP address to check for + local ip_address="${2}" + # See what IP is in the setupVars.conf file + local setup_vars_ip=$(cat ${VARSFILE} | grep IPV${protocol}_ADDRESS | cut -d '=' -f2) + # If it's an IPv6 address + if [[ "${protocol}" == "6" ]]; then + # Strip off the / + if [[ "${ip_address%/*}" == "${setup_vars_ip}" ]]; then + # if it matches, show it in green + log_write " ${COL_LIGHT_GREEN}${ip_address%/*}${COL_NC}" + else + # otherwise show it in red with an FAQ URL + log_write " ${COL_LIGHT_RED}${ip_address%/*}${COL_NC} (${FAQ_ULA})" + fi + + else + # if the protocol isn't 6, it's 4 so no need to strip the CIDR notation + # since it exists in the setupVars.conf that way + if [[ "${ip_address}" == "${setup_vars_ip}" ]]; then + # show in green if it matches + log_write " ${COL_LIGHT_GREEN}${ip_address}${COL_NC}" + else + # otherwise show it in red + log_write " ${COL_LIGHT_RED}${ip_address}${COL_NC} (${FAQ_ULA})" + fi + fi +} + detect_ip_addresses() { # First argument should be a 4 or a 6 local protocol=${1} @@ -359,7 +392,8 @@ detect_ip_addresses() { # Since there may be more than one IP address, store them in an array for i in "${!ip_addr_list[@]}"; do # For each one in the list, print it out - log_write " ${ip_addr_list[$i]}" + does_ip_match_setup_vars "${protocol}" "${ip_addr_list[$i]}" + # log_write " ${ip_addr_list[$i]}" done log_write "" else @@ -367,25 +401,36 @@ detect_ip_addresses() { log_write "${CROSS} ${COL_LIGHT_RED}No IPv${protocol} address(es) found on the ${PIHOLE_INTERFACE}${COL_NC} interace.\n" return 1 fi + # If the protocol is v6 + if [[ "${protocol}" == "6" ]]; then + # let the user know that as long as there is one green address, things should be ok + log_write " ^ Please note that you may have more than one IPv${protocol} address listed." + log_write " As long as one of them is green, it matches what is in ${VARSFILE} so there is no need for concern.\n" + log_write " The link to the FAQ is for an issue that sometimes occurs when the IPv6 address changes, which is why we check for it." + fi } - -ping_gateway() { - # First argument should be a 4 or a 6 +ping_ipv4_or_ipv6() { + # Give the first argument a readable name (a 4 or a six should be the argument) local protocol="${1}" # If the protocol is 6, if [[ ${protocol} == "6" ]]; then # use ping6 - local cmd="ping6" + cmd="ping6" # and Google's public IPv6 address - local public_address="2001:4860:4860::8888" + public_address="2001:4860:4860::8888" else # Otherwise, just use ping - local cmd="ping" + cmd="ping" # and Google's public IPv4 address - local public_address="8.8.8.8" + public_address="8.8.8.8" fi +} +ping_gateway() { + local protocol="${1}" + ping_ipv4_or_ipv6 "${protocol}" + # Check if we are using IPv4 or IPv6 # Find the default gateway using IPv4 or IPv6 local gateway gateway="$(ip -${protocol} route | grep default | cut -d ' ' -f 3)" @@ -394,13 +439,13 @@ ping_gateway() { if [[ -n "${gateway}" ]]; then log_write "${INFO} Default IPv${protocol} gateway: ${gateway}" # Let the user know we will ping the gateway for a response - log_write "* Pinging IPv${protocol} gateway..." + log_write "* Pinging ${gateway}..." # Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only, # on the pihole interface, and tail the last three lines of the output # If pinging the gateway is not successful, - if ! ${cmd} -c 3 -W 3 -n ${gateway} -I ${PIHOLE_INTERFACE} | tail -n 3; then + if ! ${cmd} -c 3 -W 2 -n ${gateway} -I ${PIHOLE_INTERFACE} >/dev/null; then # let the user know - log_write "${CROSS} ${COL_LIGHT_RED}Gateway did not respond.${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}Gateway did not respond.${COL_NC} ($FAQ_GATEWAY)\n" # and return an error code return 1 # Otherwise, @@ -414,23 +459,11 @@ ping_gateway() { } ping_internet() { - # Give the first argument a readable name (a 4 or a six should be the argument) local protocol="${1}" - # If the protocol is 6, - if [[ ${protocol} == "6" ]]; then - # use ping6 - local cmd="ping6" - # and Google's public IPv6 address - local public_address="2001:4860:4860::8888" - else - # Otherwise, just use ping - local cmd="ping" - # and Google's public IPv4 address - local public_address="8.8.8.8" - fi + ping_ipv4_or_ipv6 "${protocol}" log_write "* Checking Internet connectivity via IPv${protocol}..." # Try to ping the address 3 times - if ! ping_inet="$(${cmd} -W 3 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then + if ! ${cmd} -W 2 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} >/dev/null; then # if it's unsuccessful, show an error log_write "${CROSS} ${COL_LIGHT_RED}Cannot reach the Internet.${COL_NC}\n" return 1 @@ -658,8 +691,12 @@ parse_file() { local file_lines # For each line in the file, for file_lines in "${file_info[@]}"; do - # Display the file's content + if [[ ! -z "${file_lines}" ]]; then + # don't include the Web password hash + [[ "${file_linesline}" =~ ^\#.*$ || ! "${file_lines}" || "${file_lines}" == "WEBPASSWORD="* ]] && continue + # otherwise, display the lines of the file log_write " ${file_lines}" + fi done # Set the IFS back to what it was IFS="$OLD_IFS" @@ -823,15 +860,15 @@ upload_to_tricorder() { log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" log_write "${TICK} Your debug token is: ${COL_LIGHT_GREEN}${tricorder_token}${COL_NC}" log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" - - log_write " * Provide this token to the Pi-hole team for assistance:" + log_write "" + log_write " * Provide this token to the Pi-hole team for assistance at" log_write " * ${COL_CYAN}https://discourse.pi-hole.net${COL_NC}" - log_write " * Your log will self-destruct after ${COL_LIGHT_RED}48 hours${COL_NC}." + log_write " * Your log will self-destruct on our server after ${COL_LIGHT_RED}48 hours${COL_NC}." else log_write "${CROSS} ${COL_LIGHT_RED}There was an error uploading your debug log.${COL_NC}" log_write " * Please try again or contact the Pi-hole team for assistance." fi - log_write " * A local copy of the debug log can be found at : ${COL_CYAN}${DEBUG_LOG}${COL_NC}\n" + log_write " * A local copy of the debug log can be found at: ${COL_CYAN}${DEBUG_LOG}${COL_NC}\n" } # Run through all the functions we made From 01e091fd170229c98d33adf96a8c207717cc16ea Mon Sep 17 00:00:00 2001 From: DL6ER Date: Fri, 2 Jun 2017 23:01:48 +0200 Subject: [PATCH 063/162] Prefer ULA over GUA addresses [IPv6] (#1508) * On installs with GUA and ULA's we should prefer ULA's as it's been demonstrated that GUA's can and often are rotated by ISPs. Fixes #1473 * Add test for link-local address detection * Add ULA-only and GUA-only tests * Add test_IPv6_GUA_ULA_test and test_IPv6_ULA_GUA_test * Add "" * Add mock_command_2 command that can mock a command with more than one argument (as "ip -6 address") and result multiple lines of results * Make mock_command_2 more similar to the original mock_command * Correct comments * Fixed remaining comments * Fixed one last comment... * Fixed a comment... --- automated install/basic-install.sh | 34 +++++++++++-- test/test_automated_install.py | 76 ++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 3 deletions(-) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index 42e06bdf..b8b44550 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -327,16 +327,44 @@ chooseInterface() { fi } +# See https://github.com/pi-hole/pi-hole/issues/1473#issuecomment-301745953 +testIPv6() { + first="$(cut -f1 -d":" <<< "$1")" + value1=$(((0x$first)/256)) + value2=$(((0x$first)%256)) + ((($value1&254)==252)) && echo "ULA" || true + ((($value1&112)==32)) && echo "GUA" || true + ((($value1==254) && (($value2&192)==128))) && echo "Link-local" || true +} + useIPv6dialog() { - # Show the IPv6 address used for blocking - IPV6_ADDRESS=$(ip -6 route get 2001:4860:4860::8888 | grep -v "unreachable" | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "src") print $(i+1) }') + # Determine the IPv6 address used for blocking + IPV6_ADDRESSES=($(ip -6 address | grep 'scope global' | awk '{print $2}')) + + # Determine type of found IPv6 addresses + for i in "${IPV6_ADDRESSES[@]}"; do + result=$(testIPv6 "$i") + [[ "${result}" == "ULA" ]] && ULA_ADDRESS="$i" + [[ "${result}" == "GUA" ]] && GUA_ADDRESS="$i" + done + + # Determine which address to be used: Prefer ULA over GUA or don't use any if none found + if [[ ! -z "${ULA_ADDRESS}" ]]; then + IPV6_ADDRESS="${ULA_ADDRESS}" + echo "::: Found IPv6 ULA address, using it for blocking IPv6 ads" + elif [[ ! -z "${GUA_ADDRESS}" ]]; then + echo "::: Found IPv6 GUA address, using it for blocking IPv6 ads" + IPV6_ADDRESS="${GUA_ADDRESS}" + else + echo "::: Found neither IPv6 ULA nor GUA address, blocking IPv6 ads will not be enabled" + IPV6_ADDRESS="" + fi if [[ ! -z "${IPV6_ADDRESS}" ]]; then whiptail --msgbox --backtitle "IPv6..." --title "IPv6 Supported" "$IPV6_ADDRESS will be used to block ads." ${r} ${c} fi } - use4andor6() { local useIPv4 local useIPv6 diff --git a/test/test_automated_install.py b/test/test_automated_install.py index 8e36fc96..60772625 100644 --- a/test/test_automated_install.py +++ b/test/test_automated_install.py @@ -402,6 +402,61 @@ def test_FTL_binary_installed_and_responsive_no_errors(Pihole): # assert '644 /run/pihole-FTL.pid' in support_files.stdout # assert '644 /var/log/pihole-FTL.log' in support_files.stdout +def test_IPv6_only_link_local(Pihole): + ''' confirms IPv6 blocking is disabled for Link-local address ''' + # mock ip -6 address to return Link-local address + mock_command_2('ip', {'-6 address':('inet6 fe80::d210:52fa:fe00:7ad7/64 scope link', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found neither IPv6 ULA nor GUA address, blocking IPv6 ads will not be enabled' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_only_ULA(Pihole): + ''' confirms IPv6 blocking is enabled for ULA addresses ''' + # mock ip -6 address to return ULA address + mock_command_2('ip', {'-6 address':('inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_only_GUA(Pihole): + ''' confirms IPv6 blocking is enabled for GUA addresses ''' + # mock ip -6 address to return GUA address + mock_command_2('ip', {'-6 address':('inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 GUA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_GUA_ULA_test(Pihole): + ''' confirms IPv6 blocking is enabled for GUA and ULA addresses ''' + # mock ip -6 address to return GUA and ULA addresses + mock_command_2('ip', {'-6 address':('inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global\ninet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_ULA_GUA_test(Pihole): + ''' confirms IPv6 blocking is enabled for GUA and ULA addresses ''' + # mock ip -6 address to return ULA and GUA addresses + mock_command_2('ip', {'-6 address':('inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global\ninet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + # Helper functions def mock_command(script, args, container): ''' Allows for setup of commands we don't really want to have to run for real in unit tests ''' @@ -424,6 +479,27 @@ def mock_command(script, args, container): chmod +x {script} rm -f /var/log/{scriptlog}'''.format(script=full_script_path, content=mock_script, scriptlog=script)) +def mock_command_2(script, args, container): + ''' Allows for setup of commands we don't really want to have to run for real in unit tests ''' + full_script_path = '/usr/local/bin/{}'.format(script) + mock_script = dedent('''\ + #!/bin/bash -e + echo "\$0 \$@" >> /var/log/{script} + case "\$1 \$2" in'''.format(script=script)) + for k, v in args.iteritems(): + case = dedent(''' + \"{arg}\") + echo \"{res}\" + exit {retcode} + ;;'''.format(arg=k, res=v[0], retcode=v[1])) + mock_script += case + mock_script += dedent(''' + esac''') + container.run(''' + cat < {script}\n{content}\nEOF + chmod +x {script} + rm -f /var/log/{scriptlog}'''.format(script=full_script_path, content=mock_script, scriptlog=script)) + def run_script(Pihole, script): result = Pihole.run(script) assert result.rc == 0 From 8ef64dbe7491c9028a45b14d415bcf86d6743bbf Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 3 Jun 2017 14:51:35 +0200 Subject: [PATCH 064/162] Add weekly logrotation of FTL's log (#1509) --- advanced/logrotate | 11 +++++++++++ automated install/basic-install.sh | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/advanced/logrotate b/advanced/logrotate index 570e7548..ffed910b 100644 --- a/advanced/logrotate +++ b/advanced/logrotate @@ -8,3 +8,14 @@ notifempty nomail } + +/var/log/pihole-FTL.log { + # su # + weekly + copytruncate + rotate 3 + compress + delaycompress + notifempty + nomail +} diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index b8b44550..e8b28f62 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -1080,7 +1080,7 @@ installLogrotate() { # the local properties of the /var/log directory logusergroup="$(stat -c '%U %G' /var/log)" if [[ ! -z $logusergroup ]]; then - sed -i "s/# su #/su ${logusergroup}/" /etc/pihole/logrotate + sed -i "s/# su #/su ${logusergroup}/g;" /etc/pihole/logrotate fi echo " done!" } From 288f93c5dd3c3646991e454c461927ac057d8eba Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 3 Jun 2017 15:06:00 +0200 Subject: [PATCH 065/162] Update LICENSE of the project to EUPL v1.2 --- LICENSE | 119 +++++++++++++++++++++++--------------------------------- 1 file changed, 49 insertions(+), 70 deletions(-) diff --git a/LICENSE b/LICENSE index 9fddaad1..9ce6e5b0 100644 --- a/LICENSE +++ b/LICENSE @@ -12,81 +12,63 @@ This license applies to the whole project EXCEPT: The licenses that existed prior to this change have remained intact. ------------------------------------------------------------- +EUROPEAN UNION PUBLIC LICENCE v. 1.2 -European Union Public Licence -V. 1.1 +EUPL © the European Union 2007, 2016 -EUPL (C) the European Community 2007 - -This European Union Public Licence (the "EUPL") applies to the Work or Software (as defined below) which is provided under the terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such use is covered by a right of the copyright holder of the Work). - -The Original Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following notice immediately following the copyright notice for the Original Work: - -Licensed under the EUPL V.1.1 - -or has expressed by any other mean his willingness to license under the EUPL. +This European Union Public Licence (the EUPL) applies to the Work (as defined below) which is provided under the terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such use is covered by a right of the copyright holder of the Work). +The Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following notice immediately following the copyright notice for the Work: +Licensed under the EUPL +or has expressed by any other means his willingness to license under the EUPL. 1. Definitions In this Licence, the following terms have the following meaning: - The Licence: this Licence. - -- The Original Work or the Software: the software distributed and/or communicated by the Licensor under this Licence, available as Source Code and also as Executable Code as the case may be. - +- The Original Work: the work or software distributed or communicated by the Licensor under this Licence, available as Source Code and also as Executable Code as the case may be. - Derivative Works: the works or software that could be created by the Licensee, based upon the Original Work or modifications thereof. This Licence does not define the extent of modification or dependence on the Original Work required in order to classify a work as a Derivative Work; this extent is determined by copyright law applicable in the country mentioned in Article 15. - -- The Work: the Original Work and/or its Derivative Works. - +- The Work: the Original Work or its Derivative Works. - The Source Code: the human-readable form of the Work which is the most convenient for people to study and modify. - - The Executable Code: any code which has generally been compiled and which is meant to be interpreted by a computer as a program. - -- The Licensor: the natural or legal person that distributes and/or communicates the Work under the Licence. - +- The Licensor: the natural or legal person that distributes or communicates the Work under the Licence. - Contributor(s): any natural or legal person who modifies the Work under the Licence, or otherwise contributes to the creation of a Derivative Work. - -- The Licensee or "You": any natural or legal person who makes any usage of the Software under the terms of the Licence. - -- Distribution and/or Communication: any act of selling, giving, lending, renting, distributing, communicating, transmitting, or otherwise making available, on-line or off-line, copies of the Work or providing access to its essential functionalities at the disposal of any other natural or legal person. +- The Licensee or You: any natural or legal person who makes any usage of the Work under the terms of the Licence. +- Distribution or Communication: any act of selling, giving, lending, renting, distributing, communicating, transmitting, or otherwise making available, online or offline, copies of the Work or providing access to its essential functionalities at the disposal of any other natural or legal person. 2. Scope of the rights granted by the Licence -The Licensor hereby grants You a world-wide, royalty-free, non-exclusive, sub-licensable licence to do the following, for the duration of copyright vested in the Original Work: - +The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, sublicensable licence to do the following, for the duration of copyright vested in the Original Work: - use the Work in any circumstance and for all usage, - reproduce the Work, -- modify the Original Work, and make Derivative Works based upon the Work, +- modify the Work, and make Derivative Works based upon the Work, - communicate to the public, including the right to make available or display the Work or copies thereof to the public and perform publicly, as the case may be, the Work, - distribute the Work or copies thereof, - lend and rent the Work or copies thereof, -- sub-license rights in the Work or copies thereof. - +- sublicense rights in the Work or copies thereof. Those rights can be exercised on any media, supports and formats, whether now known or later invented, as far as the applicable law permits so. - In the countries where moral rights apply, the Licensor waives his right to exercise his moral right to the extent allowed by law in order to make effective the licence of the economic rights here above listed. - -The Licensor grants to the Licensee royalty-free, non exclusive usage rights to any patents held by the Licensor, to the extent necessary to make use of the rights granted on the Work under this Licence. +The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to any patents held by the Licensor, to the extent necessary to make use of the rights granted on the Work under this Licence. 3. Communication of the Source Code -The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to distribute and/or communicate the Work. +The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to distribute or communicate the Work. 4. Limitations on copyright -Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the exclusive rights of the rights owners in the Original Work or Software, of the exhaustion of those rights or of other applicable limitations thereto. +Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the exclusive rights of the rights owners in the Work, of the exhaustion of those rights or of other applicable limitations thereto. 5. Obligations of the Licensee The grant of the rights mentioned above is subject to some restrictions and obligations imposed on the Licensee. Those obligations are the following: -Attribution right: the Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the Licence with every copy of the Work he/she distributes and/or communicates. The Licensee must cause any Derivative Work to carry prominent notices stating that the Work has been modified and the date of modification. +Attribution right: The Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the Licence with every copy of the Work he/she distributes or communicates. The Licensee must cause any Derivative Work to carry prominent notices stating that the Work has been modified and the date of modification. -Copyleft clause: If the Licensee distributes and/or communicates copies of the Original Works or Derivative Works based upon the Original Work, this Distribution and/or Communication will be done under the terms of this Licence or of a later version of this Licence unless the Original Work is expressly distributed only under this version of the Licence. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the Work or Derivative Work that alter or restrict the terms of the Licence. +Copyleft clause: If the Licensee distributes or communicates copies of the Original Works or Derivative Works, this Distribution or Communication will be done under the terms of this Licence or of a later version of this Licence unless the Original Work is expressly distributed only under this version of the Licence - for example by communicating EUPL v. 1.2 only. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the Work or Derivative Work that alter or restrict the terms of the Licence. -Compatibility clause: If the Licensee Distributes and/or Communicates Derivative Works or copies thereof based upon both the Original Work and another work licensed under a Compatible Licence, this Distribution and/or Communication can be done under the terms of this Compatible Licence. For the sake of this clause, "Compatible Licence" refers to the licences listed in the appendix attached to this Licence. Should the Licensee’s obligations under the Compatible Licence conflict with his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail. +Compatibility clause: If the Licensee Distributes or Communicates Derivative Works or copies thereof based upon both the Work and another work licensed under a Compatible Licence, this Distribution or Communication can be done under the terms of this Compatible Licence. For the sake of this clause, Compatible Licence refers to the licences listed in the appendix attached to this Licence. Should the Licensee's obligations under the Compatible Licence conflict with his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail. -Provision of Source Code: When distributing and/or communicating copies of the Work, the Licensee will provide a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available for as long as the Licensee continues to distribute and/or communicate the Work. +Provision of Source Code: When distributing or communicating copies of the Work, the Licensee will provide a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available for as long as the Licensee continues to distribute or communicate the Work. Legal Protection: This Licence does not grant permission to use the trade names, trademarks, service marks, or names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the copyright notice. @@ -100,10 +82,8 @@ Each time You accept the Licence, the original Licensor and subsequent Contribut 7. Disclaimer of Warranty -The Work is a work in progress, which is continuously improved by numerous contributors. It is not a finished work and may therefore contain defects or "bugs" inherent to this type of software development. - -For the above reason, the Work is provided under the Licence on an "as is" basis and without warranties of any kind concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this Licence. - +The Work is a work in progress, which is continuously improved by numerous Contributors. It is not a finished work and may therefore contain defects or bugs inherent to this type of development. +For the above reason, the Work is provided under the Licence on an as is basis and without warranties of any kind concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this Licence. This disclaimer of warranty is an essential part of the Licence and a condition for the grant of any rights to the Work. 8. Disclaimer of Liability @@ -112,56 +92,55 @@ Except in the cases of wilful misconduct or damages directly caused to natural p 9. Additional agreements -While distributing the Original Work or Derivative Works, You may choose to conclude an additional agreement to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or services consistent with this Licence. However, in accepting such obligations, You may act only on your own behalf and on your sole responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by the fact You have accepted any such warranty or additional liability. +While distributing the Work, You may choose to conclude an additional agreement, defining obligations or services consistent with this Licence. However, if accepting obligations, You may act only on your own behalf and on your sole responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by the fact You have accepted any warranty or additional liability. 10. Acceptance of the Licence -The provisions of this Licence can be accepted by clicking on an icon "I agree" placed under the bottom of a window displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms and conditions. - -Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution and/or Communication by You of the Work or copies thereof. +The provisions of this Licence can be accepted by clicking on an icon I agree placed under the bottom of a window displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms and conditions. +Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution or Communication by You of the Work or copies thereof. 11. Information to the public -In case of any Distribution and/or Communication of the Work by means of electronic communication by You (for example, by offering to download the Work from a remote location) the distribution channel or media (for example, a website) must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence and the way it may be accessible, concluded, stored and reproduced by the Licensee. +In case of any Distribution or Communication of the Work by means of electronic communication by You (for example, by offering to download the Work from a remote location) the distribution channel or media (for example, a website) must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence and the way it may be accessible, concluded, stored and reproduced by the Licensee. 12. Termination of the Licence The Licence and the rights granted hereunder will terminate automatically upon any breach by the Licensee of the terms of the Licence. - Such a termination will not terminate the licences of any person who has received the Work from the Licensee under the Licence, provided such persons remain in full compliance with the Licence. 13. Miscellaneous -Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the Work licensed hereunder. - -If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or enforceability of the Licence as a whole. Such provision will be construed and/or reformed so as necessary to make it valid and enforceable. - -The European Commission may publish other linguistic versions and/or new versions of this Licence, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence. New versions of the Licence will be published with a unique version number. - +Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the Work. +If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or enforceability of the Licence as a whole. Such provision will be construed or reformed so as necessary to make it valid and enforceable. +The European Commission may publish other linguistic versions or new versions of this Licence or updated versions of the Appendix, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence. New versions of the Licence will be published with a unique version number. All linguistic versions of this Licence, approved by the European Commission, have identical value. Parties can take advantage of the linguistic version of their choice. 14. Jurisdiction -Any litigation resulting from the interpretation of this License, arising between the European Commission, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice of the European Communities, as laid down in article 238 of the Treaty establishing the European Community. - -Any litigation arising between Parties, other than the European Commission, and resulting from the interpretation of this License, will be subject to the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business. +Without prejudice to specific agreement between parties, +- any litigation resulting from the interpretation of this License, arising between the European Union institutions, bodies, offices or agencies, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice of the European Union, as laid down in article 272 of the Treaty on the Functioning of the European Union, +- any litigation arising between other parties and resulting from the interpretation of this License, will be subject to the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business. 15. Applicable Law -This Licence shall be governed by the law of the European Union country where the Licensor resides or has his registered office. - -This licence shall be governed by the Belgian law if: - -- a litigation arises between the European Commission, as a Licensor, and any Licensee; -- the Licensor, other than the European Commission, has no residence or registered office inside a European Union country. - +Without prejudice to specific agreement between parties, +- this Licence shall be governed by the law of the European Union Member State where the Licensor has his seat, resides or has his registered office, +- this licence shall be governed by Belgian law if the Licensor has no seat, residence or registered office inside a European Union Member State. === + Appendix -"Compatible Licences" according to article 5 EUPL are: -- GNU General Public License (GNU GPL) v. 2 +Compatible Licences according to Article 5 EUPL are: +- GNU General Public License (GPL) v. 2, v. 3 +- GNU Affero General Public License (AGPL) v. 3 - Open Software License (OSL) v. 2.1, v. 3.0 -- Common Public License v. 1.0 -- Eclipse Public License v. 1.0 -- Cecill v. 2.0 +- Eclipse Public License (EPL) v. 1.0 +- CeCILL v. 2.0, v. 2.1 +- Mozilla Public Licence (MPL) v. 2 +- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 +- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for works other than software +- European Union Public Licence (EUPL) v. 1.1, v. 1.2 +- Québec Free and Open-Source Licence - Reciprocity (LiLiQ-R) or Strong Reciprocity (LiLiQ-R+) +- The European Commission may update this Appendix to later versions of the above licences without producing a new version of the EUPL, as long as they provide the rights granted in Article 2 of this Licence and protect the covered Source Code from exclusive appropriation. +- All other changes or additions to this Appendix require the production of a new EUPL version. From 2516a1e298068aacc3d98d198caee10277c9460c Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 3 Jun 2017 17:23:47 +0200 Subject: [PATCH 066/162] Make clear that NO is the default if the user just hits return (#1514) --- advanced/Scripts/piholeCheckout.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh index 286edb2e..e2c0ab11 100644 --- a/advanced/Scripts/piholeCheckout.sh +++ b/advanced/Scripts/piholeCheckout.sh @@ -87,7 +87,7 @@ warning1() { echo " Please note that changing branches severely alters your Pi-hole subsystems" echo " Features that work on the master branch, may not on a development branch" echo -e " ${red}This feature is NOT supported unless a Pi-hole developer explicitly asks!${def}" - read -r -p " Have you read and understood this? [Y/N] " response + read -r -p " Have you read and understood this? [y/N] " response case ${response} in [yY][eE][sS]|[yY]) echo "::: Continuing with branch change." From 6823a6264455a28242a30b46d1a5fc759d5f12b3 Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Sun, 4 Jun 2017 03:13:40 +1000 Subject: [PATCH 067/162] Add tricorderFunc back as usable function (#1515) As per #1464 --- pihole | 1 + 1 file changed, 1 insertion(+) diff --git a/pihole b/pihole index 08e6b094..f2bc7000 100755 --- a/pihole +++ b/pihole @@ -423,5 +423,6 @@ case "${1}" in "-a" | "admin" ) webpageFunc "$@";; "-t" | "tail" ) tailFunc;; "checkout" ) piholeCheckoutFunc "$@";; + "tricorder" ) tricorderFunc;; * ) helpFunc;; esac From f1146a344356a6e9b74dc02f70d92f4f9fccf1a0 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 4 Jun 2017 12:40:57 +0200 Subject: [PATCH 068/162] Don't update FTL when there is a core update (as this will update FTL a second time). Fixes #1516 --- advanced/Scripts/update.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/advanced/Scripts/update.sh b/advanced/Scripts/update.sh index 4fceb931..24b30de4 100755 --- a/advanced/Scripts/update.sh +++ b/advanced/Scripts/update.sh @@ -117,7 +117,10 @@ main() { echo "::: FTL: up to date" fi - if ${FTL_update}; then + # Logic: Don't update FTL when there is a core update available + # since the core update will run the installer which will itself + # re-install (i.e. update) FTL + if ${FTL_update} && ! ${core_update}; then echo ":::" echo "::: FTL out of date" FTLdetect From cf6a1ac9adb4e26570cc5da7c8be628080f37e0f Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 4 Jun 2017 13:23:56 +0200 Subject: [PATCH 069/162] Add FTL tests to the test suite (#1510) * Add first version of FTL tests * Wait one second to allow FTL to start up and analyze our mock log * Add test_FTL_telnet_statistics * Added test_FTL_telnet_top_clients * Add test_FTL_telnet_top_domains --- test/FTL-test.sh | 76 ++++++++++++++++++++++++++++++++++ test/test_automated_install.py | 64 ++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100755 test/FTL-test.sh diff --git a/test/FTL-test.sh b/test/FTL-test.sh new file mode 100755 index 00000000..7e139c8a --- /dev/null +++ b/test/FTL-test.sh @@ -0,0 +1,76 @@ +#!/bin/bash +FTL_communicate() { + # Open connection to FTL + exec 3<>"/dev/tcp/localhost/4711" + + # Test if connection is open + if { "true" >&3; } 2> /dev/null; then + # Send command to FTL + echo -e ">$1" >&3 + + # Read input + read -r -t 1 LINE <&3 + until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do + echo "$LINE" >&1 + read -r -t 1 LINE <&3 + done + + # Close connection + exec 3>&- + exec 3<&- + fi +} + +FTL_get_version() { + FTL_communicate "version" +} + +FTL_get_stats() { + FTL_communicate "stats" +} + +FTL_get_top_clients() { + FTL_communicate "top-clients" +} + +FTL_get_top_domains() { + FTL_communicate "top-domains" +} + +FTL_prepare_files() { + ts=$(dnsmasq_pre) +cat <> /var/log/pihole.log +${ts} query[AAAA] raspberrypi from 127.0.0.1 +${ts} /etc/pihole/local.list raspberrypi is fda2:2001:5647:0:ba27:ebff:fe37:4205 +${ts} query[A] checkip.dyndns.org from 127.0.0.1 +${ts} forwarded checkip.dyndns.org to 2001:1608:10:25::9249:d69b +${ts} forwarded checkip.dyndns.org to 2001:1608:10:25::1c04:b12f +${ts} forwarded checkip.dyndns.org to 2620:0:ccd::2 +${ts} forwarded checkip.dyndns.org to 2620:0:ccc::2 +${ts} reply checkip.dyndns.org is +${ts} reply checkip.dyndns.com is 216.146.38.70 +${ts} reply checkip.dyndns.com is 216.146.43.71 +${ts} reply checkip.dyndns.com is 91.198.22.70 +${ts} reply checkip.dyndns.com is 216.146.43.70 +${ts} query[A] pi.hole from 10.8.0.2 +${ts} /etc/pihole/local.list pi.hole is 192.168.2.10 +${ts} query[A] play.google.com from 192.168.2.208 +${ts} forwarded play.google.com to 2001:1608:10:25::9249:d69b +${ts} forwarded play.google.com to 2001:1608:10:25::1c04:b12f +${ts} forwarded play.google.com to 2620:0:ccd::2 +${ts} forwarded play.google.com to 2620:0:ccc::2 +${ts} reply play.google.com is +${ts} reply play.l.google.com is 216.58.208.110 +${ts} reply play.l.google.com is 216.58.208.110 +${ts} reply play.l.google.com is 216.58.208.110 +${ts} reply play.google.com is +${ts} query[AAAA] play.google.com from 192.168.2.208 +${ts} forwarded play.google.com to 2620:0:ccd::2 +${ts} reply play.l.google.com is 2a00:1450:4017:802::200e +EOT +} + +dnsmasq_pre() { + echo -n $(date +"%b %e %H:%M:%S") + echo -n "dnsmasq[123]:" +} diff --git a/test/test_automated_install.py b/test/test_automated_install.py index 60772625..60a0f123 100644 --- a/test/test_automated_install.py +++ b/test/test_automated_install.py @@ -402,6 +402,70 @@ def test_FTL_binary_installed_and_responsive_no_errors(Pihole): # assert '644 /run/pihole-FTL.pid' in support_files.stdout # assert '644 /var/log/pihole-FTL.log' in support_files.stdout +def test_FTL_telnet_version(Pihole): + ''' confirms FTL binary is copied and functional in installed location and through telnet ''' + FTLtest = Pihole.run(''' + source /opt/pihole/basic-install.sh + source /etc/.pihole/test/FTL-test.sh + FTL_prepare_files + FTLdetect + pihole-FTL + sleep 1 + FTL_get_version + ''') + assert 'version' in FTLtest.stdout + assert 'tag' in FTLtest.stdout + assert 'branch' in FTLtest.stdout + assert 'date' in FTLtest.stdout + +def test_FTL_telnet_statistics(Pihole): + ''' confirms FTL binary is copied and functional in installed location and through telnet ''' + FTLtest = Pihole.run(''' + source /opt/pihole/basic-install.sh + source /etc/.pihole/test/FTL-test.sh + FTL_prepare_files + FTLdetect + pihole-FTL + sleep 1 + FTL_get_stats + ''') + assert 'domains_being_blocked' in FTLtest.stdout + assert 'dns_queries_today 5' in FTLtest.stdout + assert 'unique_domains 4' in FTLtest.stdout + assert 'queries_forwarded 3' in FTLtest.stdout + assert 'queries_cached 2' in FTLtest.stdout + +def test_FTL_telnet_top_clients(Pihole): + ''' confirms FTL binary is copied and functional in installed location and through telnet ''' + FTLtest = Pihole.run(''' + source /opt/pihole/basic-install.sh + source /etc/.pihole/test/FTL-test.sh + FTL_prepare_files + FTLdetect + pihole-FTL + sleep 1 + FTL_get_top_clients + ''') + assert '0 2 192.168.2.208' in FTLtest.stdout + assert '1 2 127.0.0.1' in FTLtest.stdout + assert '2 1 10.8.0.2' in FTLtest.stdout + +def test_FTL_telnet_top_domains(Pihole): + ''' confirms FTL binary is copied and functional in installed location and through telnet ''' + FTLtest = Pihole.run(''' + source /opt/pihole/basic-install.sh + source /etc/.pihole/test/FTL-test.sh + FTL_prepare_files + FTLdetect + pihole-FTL + sleep 1 + FTL_get_top_domains + ''') + assert '0 2 play.google.com' in FTLtest.stdout + assert '1 1 pi.hole' in FTLtest.stdout + assert '2 1 checkip.dyndns.org' in FTLtest.stdout + assert '3 1 raspberrypi' in FTLtest.stdout + def test_IPv6_only_link_local(Pihole): ''' confirms IPv6 blocking is disabled for Link-local address ''' # mock ip -6 address to return Link-local address From 939055f19c2e2389b9a9db8db263f9cd26838a17 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 5 Jun 2017 13:51:13 +0200 Subject: [PATCH 070/162] Revert "Add FTL tests to the test suite (#1510)" (#1519) This reverts commit cf6a1ac9adb4e26570cc5da7c8be628080f37e0f. --- test/FTL-test.sh | 76 ---------------------------------- test/test_automated_install.py | 64 ---------------------------- 2 files changed, 140 deletions(-) delete mode 100755 test/FTL-test.sh diff --git a/test/FTL-test.sh b/test/FTL-test.sh deleted file mode 100755 index 7e139c8a..00000000 --- a/test/FTL-test.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash -FTL_communicate() { - # Open connection to FTL - exec 3<>"/dev/tcp/localhost/4711" - - # Test if connection is open - if { "true" >&3; } 2> /dev/null; then - # Send command to FTL - echo -e ">$1" >&3 - - # Read input - read -r -t 1 LINE <&3 - until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do - echo "$LINE" >&1 - read -r -t 1 LINE <&3 - done - - # Close connection - exec 3>&- - exec 3<&- - fi -} - -FTL_get_version() { - FTL_communicate "version" -} - -FTL_get_stats() { - FTL_communicate "stats" -} - -FTL_get_top_clients() { - FTL_communicate "top-clients" -} - -FTL_get_top_domains() { - FTL_communicate "top-domains" -} - -FTL_prepare_files() { - ts=$(dnsmasq_pre) -cat <> /var/log/pihole.log -${ts} query[AAAA] raspberrypi from 127.0.0.1 -${ts} /etc/pihole/local.list raspberrypi is fda2:2001:5647:0:ba27:ebff:fe37:4205 -${ts} query[A] checkip.dyndns.org from 127.0.0.1 -${ts} forwarded checkip.dyndns.org to 2001:1608:10:25::9249:d69b -${ts} forwarded checkip.dyndns.org to 2001:1608:10:25::1c04:b12f -${ts} forwarded checkip.dyndns.org to 2620:0:ccd::2 -${ts} forwarded checkip.dyndns.org to 2620:0:ccc::2 -${ts} reply checkip.dyndns.org is -${ts} reply checkip.dyndns.com is 216.146.38.70 -${ts} reply checkip.dyndns.com is 216.146.43.71 -${ts} reply checkip.dyndns.com is 91.198.22.70 -${ts} reply checkip.dyndns.com is 216.146.43.70 -${ts} query[A] pi.hole from 10.8.0.2 -${ts} /etc/pihole/local.list pi.hole is 192.168.2.10 -${ts} query[A] play.google.com from 192.168.2.208 -${ts} forwarded play.google.com to 2001:1608:10:25::9249:d69b -${ts} forwarded play.google.com to 2001:1608:10:25::1c04:b12f -${ts} forwarded play.google.com to 2620:0:ccd::2 -${ts} forwarded play.google.com to 2620:0:ccc::2 -${ts} reply play.google.com is -${ts} reply play.l.google.com is 216.58.208.110 -${ts} reply play.l.google.com is 216.58.208.110 -${ts} reply play.l.google.com is 216.58.208.110 -${ts} reply play.google.com is -${ts} query[AAAA] play.google.com from 192.168.2.208 -${ts} forwarded play.google.com to 2620:0:ccd::2 -${ts} reply play.l.google.com is 2a00:1450:4017:802::200e -EOT -} - -dnsmasq_pre() { - echo -n $(date +"%b %e %H:%M:%S") - echo -n "dnsmasq[123]:" -} diff --git a/test/test_automated_install.py b/test/test_automated_install.py index 60a0f123..60772625 100644 --- a/test/test_automated_install.py +++ b/test/test_automated_install.py @@ -402,70 +402,6 @@ def test_FTL_binary_installed_and_responsive_no_errors(Pihole): # assert '644 /run/pihole-FTL.pid' in support_files.stdout # assert '644 /var/log/pihole-FTL.log' in support_files.stdout -def test_FTL_telnet_version(Pihole): - ''' confirms FTL binary is copied and functional in installed location and through telnet ''' - FTLtest = Pihole.run(''' - source /opt/pihole/basic-install.sh - source /etc/.pihole/test/FTL-test.sh - FTL_prepare_files - FTLdetect - pihole-FTL - sleep 1 - FTL_get_version - ''') - assert 'version' in FTLtest.stdout - assert 'tag' in FTLtest.stdout - assert 'branch' in FTLtest.stdout - assert 'date' in FTLtest.stdout - -def test_FTL_telnet_statistics(Pihole): - ''' confirms FTL binary is copied and functional in installed location and through telnet ''' - FTLtest = Pihole.run(''' - source /opt/pihole/basic-install.sh - source /etc/.pihole/test/FTL-test.sh - FTL_prepare_files - FTLdetect - pihole-FTL - sleep 1 - FTL_get_stats - ''') - assert 'domains_being_blocked' in FTLtest.stdout - assert 'dns_queries_today 5' in FTLtest.stdout - assert 'unique_domains 4' in FTLtest.stdout - assert 'queries_forwarded 3' in FTLtest.stdout - assert 'queries_cached 2' in FTLtest.stdout - -def test_FTL_telnet_top_clients(Pihole): - ''' confirms FTL binary is copied and functional in installed location and through telnet ''' - FTLtest = Pihole.run(''' - source /opt/pihole/basic-install.sh - source /etc/.pihole/test/FTL-test.sh - FTL_prepare_files - FTLdetect - pihole-FTL - sleep 1 - FTL_get_top_clients - ''') - assert '0 2 192.168.2.208' in FTLtest.stdout - assert '1 2 127.0.0.1' in FTLtest.stdout - assert '2 1 10.8.0.2' in FTLtest.stdout - -def test_FTL_telnet_top_domains(Pihole): - ''' confirms FTL binary is copied and functional in installed location and through telnet ''' - FTLtest = Pihole.run(''' - source /opt/pihole/basic-install.sh - source /etc/.pihole/test/FTL-test.sh - FTL_prepare_files - FTLdetect - pihole-FTL - sleep 1 - FTL_get_top_domains - ''') - assert '0 2 play.google.com' in FTLtest.stdout - assert '1 1 pi.hole' in FTLtest.stdout - assert '2 1 checkip.dyndns.org' in FTLtest.stdout - assert '3 1 raspberrypi' in FTLtest.stdout - def test_IPv6_only_link_local(Pihole): ''' confirms IPv6 blocking is disabled for Link-local address ''' # mock ip -6 address to return Link-local address From 92b5fe4be45552aff30f7acbbe78bca9ec0e67cd Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 5 Jun 2017 14:55:58 -0500 Subject: [PATCH 071/162] check arch compatibility and add gateway faq url --- advanced/Scripts/piholeDebug.sh | 39 +++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 954c6c31..7ad503bb 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -1,4 +1,4 @@ -check_critical_program_versions#!/usr/bin/env bash +#!/usr/bin/env bash # Pi-hole: A black hole for Internet advertisements # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. @@ -57,8 +57,9 @@ fi FAQ_UPDATE_PI_HOLE="${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC}" FAQ_CHECKOUT_COMMAND="${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC}" FAQ_HARDWARE_REQUIREMENTS="${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273${COL_NC}" -FAQ_GATEWAY="${COL_CYAN}https://discourse.pi-hole.net/{PLACEHOLDER}${COL_NC}" +FAQ_GATEWAY="${COL_CYAN}https://discourse.pi-hole.net/t/why-is-a-default-gateway-important-for-pi-hole/3546${COL_NC}" FAQ_ULA="${COL_CYAN}https://discourse.pi-hole.net/t/use-ipv6-ula-addresses-for-pi-hole/2127${COL_NC}" +FAQ_FTL_COMPATIBILITY="${COL_CYAN}https://github.com/pi-hole/FTL#compatibility-list${COL_NC}" source_setup_variables() { # Display the current test that is running @@ -330,10 +331,24 @@ processor_check() { # If it does not contain a value, if [[ -z "${PROCESSOR}" ]]; then # we couldn't detect it, so show an error - log_write "${CROSS} ${COL_LIGHT_RED}Processor could not be identified.${COL_NC}" + PROCESSOR=$(lscpu | awk '/Architecture/ {print $2}') + log_write "${CROSS} ${COL_LIGHT_RED}${PROCESSOR}${COL_NC} has not been tested with FTL, but may still work: (${FAQ_FTL_COMPATIBILITY})" else + # Check if the architecture is currently supported for FTL + case "${PROCESSOR}" in + "amd64") "${TICK} ${COL_LIGHT_GREEN}${PROCESSOR}${COL_NC}" + ;; + "armv6l") "${TICK} ${COL_LIGHT_GREEN}${PROCESSOR}${COL_NC}" + ;; + "armv6") "${TICK} ${COL_LIGHT_GREEN}${PROCESSOR}${COL_NC}" + ;; + "armv7l") "${TICK} ${COL_LIGHT_GREEN}${PROCESSOR}${COL_NC}" + ;; + "aarch64") "${TICK} ${COL_LIGHT_GREEN}${PROCESSOR}${COL_NC}" + ;; # Otherwise, show the processor type - log_write "${INFO} ${PROCESSOR}" + *) log_write "${INFO} ${PROCESSOR}"; + esac fi } @@ -356,10 +371,10 @@ does_ip_match_setup_vars() { # Strip off the / if [[ "${ip_address%/*}" == "${setup_vars_ip}" ]]; then # if it matches, show it in green - log_write " ${COL_LIGHT_GREEN}${ip_address%/*}${COL_NC}" + log_write " ${COL_LIGHT_GREEN}${ip_address%/*}${COL_NC} matches the IP found in ${VARSFILE}" else # otherwise show it in red with an FAQ URL - log_write " ${COL_LIGHT_RED}${ip_address%/*}${COL_NC} (${FAQ_ULA})" + log_write " ${COL_LIGHT_RED}${ip_address%/*}${COL_NC} does not match the IP found in ${VARSFILE}(${FAQ_ULA})" fi else @@ -367,10 +382,10 @@ does_ip_match_setup_vars() { # since it exists in the setupVars.conf that way if [[ "${ip_address}" == "${setup_vars_ip}" ]]; then # show in green if it matches - log_write " ${COL_LIGHT_GREEN}${ip_address}${COL_NC}" + log_write " ${COL_LIGHT_GREEN}${ip_address}${COL_NC} matches the IP found in ${VARSFILE}" else # otherwise show it in red - log_write " ${COL_LIGHT_RED}${ip_address}${COL_NC} (${FAQ_ULA})" + log_write " ${COL_LIGHT_RED}${ip_address}${COL_NC} does not match the IP found in ${VARSFILE} (${FAQ_ULA})" fi fi } @@ -404,9 +419,9 @@ detect_ip_addresses() { # If the protocol is v6 if [[ "${protocol}" == "6" ]]; then # let the user know that as long as there is one green address, things should be ok - log_write " ^ Please note that you may have more than one IPv${protocol} address listed." - log_write " As long as one of them is green, it matches what is in ${VARSFILE} so there is no need for concern.\n" - log_write " The link to the FAQ is for an issue that sometimes occurs when the IPv6 address changes, which is why we check for it." + log_write " ^ Please note that you may have more than one IP address listed." + log_write " As long as one of them is green, and it matches what is in ${VARSFILE}, there is no need for concern.\n" + log_write " The link to the FAQ is for an issue that sometimes occurs when the IPv6 address changes, which is why we check for it.\n" fi } @@ -569,7 +584,7 @@ dig_at() { # Store the arguments as variables with names local protocol="${1}" local IP="${2}" - echo_current_diagnostic "Domain name resolution (IPv${protocol}) using a random blocked domain" + echo_current_diagnostic "Name resolution (IPv${protocol}) using a random blocked domain and a known ad-serving domain" # Set more local variables local url local local_dig From 24aa72c19d1b81be2d341712f33f619eb0b73da9 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Wed, 7 Jun 2017 12:25:00 -0500 Subject: [PATCH 072/162] condense repetative code into functions; parse the content of each file --- advanced/Scripts/piholeDebug.sh | 62 ++++++++++++--------------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 7ad503bb..187bfba2 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -24,7 +24,7 @@ SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS") VARSFILE="/etc/pihole/setupVars.conf" DEBUG_LOG="/var/log/pihole_debug.log" DNSMASQFILE="/etc/dnsmasq.conf" -DNSMASQCONFDIR="/etc/dnsmasq.d/*" +DNSMASQCONFDIR="/etc/dnsmasq.d" LIGHTTPDFILE="/etc/lighttpd/lighttpd.conf" LIGHTTPDERRFILE="/var/log/lighttpd/error.log" GRAVITYFILE="/etc/pihole/gravity.list" @@ -37,6 +37,9 @@ ADMINGITDIR="/var/www/html/admin/" WHITELISTMATCHES="/tmp/whitelistmatches.list" readonly FTLLOG="/var/log/pihole-FTL.log" coltable=/opt/pihole/COL_TABLE +FTL_LOG="/var/log/pihole-FTL.log" +FTL_PID="/run/pihole-FTL.pid" +FTL_PORT="/run/pihole-FTL.port" # These provide the colors we need for making the log more readable if [[ -f ${coltable} ]]; then @@ -673,6 +676,7 @@ process_status(){ make_array_from_file() { local filename="${1}" + local file_content=() # If the file is a directory if [[ -d "${filename}" ]]; then # do nothing since it cannot be parsed @@ -682,7 +686,7 @@ make_array_from_file() { while IFS= read -r line;do # Strip out comments and blank lines new_line=$(echo "${line}" | sed -e 's/#.*$//' -e '/^$/d') - # If the line still has content + # If the line still has content (a non-zero value) if [[ -n "${new_line}" ]]; then # Put it into the array file_content+=("${new_line}") @@ -750,59 +754,42 @@ list_files_in_dir() { # Set the first argument passed to tihs function as a named variable for better readability local dir_to_parse="${1}" # Store the files found in an array - files_found=( $(ls "${dir_to_parse}") ) - # For each file in the arry, + local files_found=( $(ls "${dir_to_parse}") ) + # For each file in the array, for each_file in "${files_found[@]}"; do if [[ -d "${each_file}" ]]; then + # If it's a directoy, do nothing : else - # display the information with the ${INFO} icon - # Also print the permissions and the user/group + # Othwerise, display the filename log_write "\n${COL_LIGHT_GREEN}$(ls -ld ${dir_to_parse}/${each_file})${COL_NC}" - # Otherwise, parse the file's content + # Then, parse the file's content into an array so each line can be analyzed if need be make_array_from_file "${dir_to_parse}/${each_file}" for each_line in "${file_content[@]}"; do log_write " ${each_line}" done fi - file_content=() done } -check_dnsmasq_d() { +show_content_of_files_in_dir() { # Set a local variable for better readability - local directory=/etc/dnsmasq.d + local directory="${1}" # Check if the directory exists dir_check "${directory}" # if it does, list the files in it list_files_in_dir "${directory}" } -check_lighttpd_d() { - # Set a local variable for better readability - local directory=/etc/lighttpd - # Check if the directory exists - dir_check "${directory}" - # if it does, list the files in it - list_files_in_dir "${directory}" -} - -check_cron_d() { - # Set a local variable for better readability - local directory=/etc/cron.d - # Check if the directory exists - dir_check "${directory}" - # if it does, list the files in it - list_files_in_dir "${directory}" -} - -check_http_directory() { - # Set a local variable for better readability - local directory=/var/www/html - # Check if the directory exists - dir_check "${directory}" - # if it does, list the files in it - list_files_in_dir "${directory}" +show_content_of_pihole_files() { + # Show the content of the files in /etc/dnsmasq.d + show_content_of_files_in_dir "${DNSMASQCONFDIR}" + # Show the content of the files in /etc/lighttpd + show_content_of_files_in_dir "/etc/lighttpd" + # Show the content of the files in /etc/lighttpd + show_content_of_files_in_dir "/etc/cron.d" + # Show the content of the files in /var/www/html + # show_content_of_files_in_dir "${ADMINGITDIR}" } analyze_gravity_list() { @@ -902,9 +889,6 @@ process_status parse_setup_vars check_x_headers analyze_gravity_list -check_dnsmasq_d -# check_lighttpd_d -# check_http_directory -# check_cron_d +show_content_of_pihole_files copy_to_debug_log upload_to_tricorder From 048eacd3050dcb1a5a11b0998ea5e9fafabf5eb6 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Wed, 7 Jun 2017 12:31:08 -0500 Subject: [PATCH 073/162] parse array in correct location --- advanced/Scripts/piholeDebug.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 187bfba2..a488248a 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -695,6 +695,9 @@ make_array_from_file() { : fi done < "${filename}" + for each_line in "${file_content[@]}"; do + log_write " ${each_line}" + done fi } @@ -765,9 +768,6 @@ list_files_in_dir() { log_write "\n${COL_LIGHT_GREEN}$(ls -ld ${dir_to_parse}/${each_file})${COL_NC}" # Then, parse the file's content into an array so each line can be analyzed if need be make_array_from_file "${dir_to_parse}/${each_file}" - for each_line in "${file_content[@]}"; do - log_write " ${each_line}" - done fi done } From 64171fa2a11140d38432f0dbc24da180212df372 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Fri, 9 Jun 2017 15:42:54 -0500 Subject: [PATCH 074/162] small color and formatting changes --- advanced/Scripts/piholeDebug.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index a488248a..f2dabc14 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -259,7 +259,7 @@ get_program_version() { log_write "${CROSS} ${COL_LIGHT_RED}${program_name} version could not be detected.${COL_NC}" else # Otherwise, display the version - log_write "${TICK} ${program_name}: ${program_version}" + log_write "${INFO} ${program_version}" fi } @@ -377,7 +377,7 @@ does_ip_match_setup_vars() { log_write " ${COL_LIGHT_GREEN}${ip_address%/*}${COL_NC} matches the IP found in ${VARSFILE}" else # otherwise show it in red with an FAQ URL - log_write " ${COL_LIGHT_RED}${ip_address%/*}${COL_NC} does not match the IP found in ${VARSFILE}(${FAQ_ULA})" + log_write " ${COL_LIGHT_RED}${ip_address%/*}${COL_NC} does not match the IP found in ${VARSFILE} (${FAQ_ULA})" fi else @@ -457,7 +457,7 @@ ping_gateway() { if [[ -n "${gateway}" ]]; then log_write "${INFO} Default IPv${protocol} gateway: ${gateway}" # Let the user know we will ping the gateway for a response - log_write "* Pinging ${gateway}..." + log_write " * Pinging ${gateway}..." # Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only, # on the pihole interface, and tail the last three lines of the output # If pinging the gateway is not successful, @@ -621,10 +621,10 @@ dig_at() { # First, do a dig on localhost to see if Pi-hole can use itself to block a domain if local_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then # If it can, show sucess - log_write "${TICK} ${random_url} ${COL_LIGHT_GREEN}is ${local_dig}${COL_NC} via localhost (${local_address})" + log_write "${TICK} ${random_url} ${COL_LIGHT_GREEN}is ${local_dig}${COL_NC} via ${COL_CYAN}localhost$COL_NC (${local_address})" else # Otherwise, show a failure - log_write "${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} ${COL_LIGHT_RED}via localhost${COL_NC} (${local_address})" + log_write "${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} via ${COL_LIGHT_RED}localhost${COL_NC} (${local_address})" fi # Next we need to check if Pi-hole can resolve a domain when the query is sent to it's IP address @@ -635,20 +635,20 @@ dig_at() { # If Pi-hole can dig itself from it's IP (not the loopback address) if pihole_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then # show a success - log_write "${TICK} ${random_url} ${COL_LIGHT_GREEN}is ${pihole_dig}${COL_NC} via Pi-hole (${pihole_address})" + log_write "${TICK} ${random_url} ${COL_LIGHT_GREEN}is ${pihole_dig}${COL_NC} via ${COL_CYAN}Pi-hole${COL_NC} (${pihole_address})" else # Othewise, show a failure - log_write "${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} ${COL_LIGHT_RED}via Pi-hole${COL_NC} (${pihole_address})" + log_write "${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${random_url} via ${COL_LIGHT_RED}Pi-hole${COL_NC} (${pihole_address})" fi # Finally, we need to make sure legitimate queries can out to the Internet using an external, public DNS server # We are using the static remote_url here instead of a random one because we know it works with IPv4 and IPv6 if remote_dig=$(dig +tries=1 +time=2 -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then # If successful, the real IP of the domain will be returned instead of Pi-hole's IP - log_write "${TICK} ${remote_url} ${COL_LIGHT_GREEN}is ${remote_dig}${COL_NC} via a remote, public DNS server (${remote_address})" + log_write "${TICK} ${remote_url} ${COL_LIGHT_GREEN}is ${remote_dig}${COL_NC} via ${COL_CYAN}a remote, public DNS server${COL_NC} (${remote_address})" else # Otherwise, show an error - log_write "${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${remote_url} ${COL_LIGHT_RED}via a remote, public DNS server${COL_NC} (${remote_address})" + log_write "${CROSS} ${COL_LIGHT_RED}Failed to resolve${COL_NC} ${remote_url} via ${COL_LIGHT_RED}a remote, public DNS server${COL_NC} (${remote_address})" fi } @@ -741,7 +741,7 @@ dir_check() { # Set the first argument passed to tihs function as a named variable for better readability local directory="${1}" # Display the current test that is running - echo_current_diagnostic "contents of ${directory}" + echo_current_diagnostic "contents of ${COL_CYAN}${directory}${COL_NC}" # For each file in the directory, for filename in "${directory}"; do # check if exists first; if it does, @@ -749,7 +749,7 @@ dir_check() { # do nothing : || \ # Otherwise, show an error - echo_succes_or_fail "${COL_LIGHT_RED}directory does not exist.${COL_NC}" + echo_succes_or_fail "${COL_LIGHT_RED}${directory} does not exist.${COL_NC}" done } From b4f1fe08f0cc83a8aa760002b3621c3668d8896a Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Fri, 9 Jun 2017 23:22:37 -0500 Subject: [PATCH 075/162] variablize all files and directories. also put required files and folders into an arry so we can compare them in later functions by parsing through them --- advanced/Scripts/piholeDebug.sh | 202 +++++++++++++++++++++++--------- 1 file changed, 146 insertions(+), 56 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index f2dabc14..fe2bf36b 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -19,31 +19,14 @@ set -o pipefail #IFS=$'\n\t' ######## GLOBAL VARS ######## -SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS") - -VARSFILE="/etc/pihole/setupVars.conf" -DEBUG_LOG="/var/log/pihole_debug.log" -DNSMASQFILE="/etc/dnsmasq.conf" -DNSMASQCONFDIR="/etc/dnsmasq.d" -LIGHTTPDFILE="/etc/lighttpd/lighttpd.conf" -LIGHTTPDERRFILE="/var/log/lighttpd/error.log" -GRAVITYFILE="/etc/pihole/gravity.list" -WHITELISTFILE="/etc/pihole/whitelist.txt" -BLACKLISTFILE="/etc/pihole/blacklist.txt" -ADLISTFILE="/etc/pihole/adlists.list" -PIHOLELOG="/var/log/pihole.log" -PIHOLEGITDIR="/etc/.pihole/" -ADMINGITDIR="/var/www/html/admin/" -WHITELISTMATCHES="/tmp/whitelistmatches.list" -readonly FTLLOG="/var/log/pihole-FTL.log" -coltable=/opt/pihole/COL_TABLE -FTL_LOG="/var/log/pihole-FTL.log" -FTL_PID="/run/pihole-FTL.pid" -FTL_PORT="/run/pihole-FTL.port" +# These variables would normally be next to the other files +# but we need them to be first in order to get the colors needed for the script output +PIHOLE_SCRIPTS_DIRECTORY="/opt/pihole" +PIHOLE_COLTABLE_FILE="${PIHOLE_SCRIPTS_DIRECTORY}/COL_TABLE" # These provide the colors we need for making the log more readable -if [[ -f ${coltable} ]]; then - source ${coltable} +if [[ -f ${PIHOLE_COLTABLE_FILE} ]]; then + source ${PIHOLE_COLTABLE_FILE} else COL_NC='\e[0m' # No Color COL_YELLOW='\e[1;33m' @@ -56,7 +39,7 @@ else OVER="\r\033[K" fi -# FAQ URLs +# FAQ URLs for use in showing the debug log FAQ_UPDATE_PI_HOLE="${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC}" FAQ_CHECKOUT_COMMAND="${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC}" FAQ_HARDWARE_REQUIREMENTS="${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273${COL_NC}" @@ -64,16 +47,123 @@ FAQ_GATEWAY="${COL_CYAN}https://discourse.pi-hole.net/t/why-is-a-default-gateway FAQ_ULA="${COL_CYAN}https://discourse.pi-hole.net/t/use-ipv6-ula-addresses-for-pi-hole/2127${COL_NC}" FAQ_FTL_COMPATIBILITY="${COL_CYAN}https://github.com/pi-hole/FTL#compatibility-list${COL_NC}" +# Other URLs we may use +FORUMS_URL="${COL_CYAN}https://discourse.pi-hole.net${COL_NC}" +TRICORDER_CONTEST="${COL_CYAN}https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/${COL_NC}" + +# Port numbers used for uploading the debug log +TRICORDER_NC_PORT_NUMBER=9999 +TRICORDER_SSL_PORT_NUMBER=9998 + +# Directories required by Pi-hole +# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684 +CORE_GIT_DIRECTORY="/etc/.pihole" +CRON_D_DIRECTORY="/etc/cron.d" +DNSMASQ_D_DIRECTORY="/etc/dnsmasq.d" +PIHOLE_DIRECTORY="/etc/pihole" +PIHOLE_SCRIPTS_DIRECTORY="/opt/pihole" +BIN_DIRECTORY="/usr/local/bin" +RUN_DIRECTORY="/run" +LOG_DIRECTORY="/var/log" +WEB_SERVER_LOG_DIRECTORY="${LOG_DIRECTORY}/lighttpd" +WEB_SERVER_CONFIG_DIRECTORY="/etc/lighttpd" +HTML_DIRECTORY="/var/www/html" +WEB_GIT_DIRECTORY="${HTML_DIRECTORY}/admin" +BLOCK_PAGE_DIRECTORY="${HTML_DIRECTORY}/pihole" + +# Files required by Pi-hole +# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684 +PIHOLE_CRON_FILE="${CRON_D_DIRECTORY}/pihole" + +PIHOLE_DNS_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/01-pihole.conf" +PIHOLE_DHCP_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/02-pihole-dhcp.conf" +PIHOLE_WILDCARD_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/03-wildcard.conf" + +WEB_SERVER_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/lighttpd.conf" + +PIHOLE_DEFAULT_AD_LISTS="${PIHOLE_DIRECTORY}/adlists.default" +PIHOLE_USER_DEFINED_AD_LISTS="${PIHOLE_DIRECTORY}/adlists.list" +PIHOLE_BLACKLIST_FILE="${PIHOLE_DIRECTORY}/blacklist.txt" +PIHOLE_BLOCKLIST_FILE="${PIHOLE_DIRECTORY}/gravity.list" +PIHOLE_INSTALL_LOG_FILE="${PIHOLE_DIRECTORY}/install.log" +PIHOLE_RAW_BLOCKLIST_FILES=${PIHOLE_DIRECTORY}/list.* +PIHOLE_LOCAL_HOSTS_FILE="${PIHOLE_DIRECTORY}/local.list" +PIHOLE_LOGROTATE_FILE="${PIHOLE_DIRECTORY}/logrotate" +PIHOLE_SETUP_VARS_FILE="${PIHOLE_DIRECTORY}/setupVars.conf" +PIHOLE_WHITELIST_FILE="${PIHOLE_DIRECTORY}/whitelist.txt" + +PIHOLE_COMMAND="${BIN_DIRECTORY}/pihole" +PIHOLE_COLTABLE_FILE="${BIN_DIRECTORY}/COL_TABLE" + +FTL_PID="${RUN_DIRECTORY}/pihole-FTL.pid" +FTL_PORT="${RUN_DIRECTORY}/pihole-FTL.port" + +PIHOLE_LOG="${LOG_DIRECTORY}/pihole.log" +PIHOLE_LOG_GZIPS=${LOG_DIRECTORY}/pihole.log.[0-9].* +PIHOLE_DEBUG_LOG="${LOG_DIRECTORY}/pihole_debug.log" +PIHOLE_FTL_LOG="${LOG_DIRECTORY}/pihole-FTL.log" + +PIHOLE_WEB_SERVER_ACCESS_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/access.log" +PIHOLE_WEB_SERVER_ERROR_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/error.log" + +# An array of operating system "pretty names" that we officialy support +# We can loop through the array at any time to see if it matches a value +SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS") + +# In a similar fashion, these are the folders Pi-hole needs +# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684 +REQUIRED_DIRECTORIES=(${CORE_GIT_DIRECTORY} +${CRON_D_DIRECTORY} +${DNSMASQ_D_DIRECTORY} +${PIHOLE_DIRECTORY} +${PIHOLE_SCRIPTS_DIRECTORY} +${BIN_DIRECTORY} +${RUN_DIRECTORY} +${LOG_DIRECTORY} +${WEB_SERVER_LOG_DIRECTORY} +${WEB_SERVER_CONFIG_DIRECTORY} +${HTML_DIRECTORY} +${WEB_GIT_DIRECTORY} +${BLOCK_PAGE_DIRECTORY}) + +# These are the files Pi-hole needs--also stored in array for parsing through +# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684 +REQUIRED_FILES=(${PIHOLE_CRON_FILE} +${PIHOLE_DNS_CONFIG_FILE} +${PIHOLE_DHCP_CONFIG_FILE} +${PIHOLE_WILDCARD_CONFIG_FILE} +${WEB_SERVER_CONFIG_FILE} +${PIHOLE_DEFAULT_AD_LISTS} +${PIHOLE_USER_DEFINED_AD_LISTS} +${PIHOLE_BLACKLIST_FILE} +${PIHOLE_BLOCKLIST_FILE} +${PIHOLE_INSTALL_LOG_FILE} +${PIHOLE_RAW_BLOCKLIST_FILES} +${PIHOLE_LOCAL_HOSTS_FILE} +${PIHOLE_LOGROTATE_FILE} +${PIHOLE_SETUP_VARS_FILE} +${PIHOLE_WHITELIST_FILE} +${PIHOLE_COMMAND} +${PIHOLE_COLTABLE_FILE} +${FTL_PID} +${FTL_PORT} +${PIHOLE_LOG} +${PIHOLE_LOG_GZIPS} +${PIHOLE_DEBUG_LOG} +${PIHOLE_FTL_LOG} +${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE} +${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}) + source_setup_variables() { # Display the current test that is running - log_write "\n${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC} Sourcing setup varibles" + log_write "\n${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC} Sourcing setup variables" # If the variable file exists, - if_file_exists "${VARSFILE}" && \ - log_write "${INFO} Sourcing ${VARSFILE}..."; + if_file_exists "${PIHOLE_SETUP_VARS_FILE}" && \ + log_write "${INFO} Sourcing ${PIHOLE_SETUP_VARS_FILE}..."; # source it - source ${VARSFILE} || \ + source ${PIHOLE_SETUP_VARS_FILE} || \ # If it can't, show an error - log_write "${VARSFILE} ${COL_LIGHT_RED}does not exist or cannot be read.${COL_NC}" + log_write "${PIHOLE_SETUP_VARS_FILE} ${COL_LIGHT_RED}does not exist or cannot be read.${COL_NC}" } make_temporary_log() { @@ -93,7 +183,7 @@ log_write() { copy_to_debug_log() { # Copy the contents of file descriptor 3 into the debug log so it can be uploaded to tricorder - cat /proc/$$/fd/3 >> "${DEBUG_LOG}" + cat /proc/$$/fd/3 >> "${PIHOLE_DEBUG_LOG}" } echo_succes_or_fail() { @@ -232,9 +322,9 @@ check_ftl_version() { # Checks the core version of the Pi-hole codebase check_component_versions() { # Check the Web version, branch, and commit - compare_local_version_to_git_version "${PIHOLEGITDIR}" "Core" + compare_local_version_to_git_version "${CORE_GIT_DIRECTORY}" "Core" # Check the Web version, branch, and commit - compare_local_version_to_git_version "${ADMINGITDIR}" "Web" + compare_local_version_to_git_version "${WEB_GIT_DIRECTORY}" "Web" # Check the FTL version check_ftl_version } @@ -357,9 +447,9 @@ processor_check() { parse_setup_vars() { echo_current_diagnostic "Setup variables" - if_file_exists "${VARSFILE}" && \ - parse_file "${VARSFILE}" || \ - log_write "${CROSS} ${COL_LIGHT_RED}Could not read ${VARSFILE}.${COL_NC}" + if_file_exists "${PIHOLE_SETUP_VARS_FILE}" && \ + parse_file "${PIHOLE_SETUP_VARS_FILE}" || \ + log_write "${CROSS} ${COL_LIGHT_RED}Could not read ${PIHOLE_SETUP_VARS_FILE}.${COL_NC}" } does_ip_match_setup_vars() { @@ -368,16 +458,16 @@ does_ip_match_setup_vars() { # IP address to check for local ip_address="${2}" # See what IP is in the setupVars.conf file - local setup_vars_ip=$(cat ${VARSFILE} | grep IPV${protocol}_ADDRESS | cut -d '=' -f2) + local setup_vars_ip=$(cat ${PIHOLE_SETUP_VARS_FILE} | grep IPV${protocol}_ADDRESS | cut -d '=' -f2) # If it's an IPv6 address if [[ "${protocol}" == "6" ]]; then # Strip off the / if [[ "${ip_address%/*}" == "${setup_vars_ip}" ]]; then # if it matches, show it in green - log_write " ${COL_LIGHT_GREEN}${ip_address%/*}${COL_NC} matches the IP found in ${VARSFILE}" + log_write " ${COL_LIGHT_GREEN}${ip_address%/*}${COL_NC} matches the IP found in ${PIHOLE_SETUP_VARS_FILE}" else # otherwise show it in red with an FAQ URL - log_write " ${COL_LIGHT_RED}${ip_address%/*}${COL_NC} does not match the IP found in ${VARSFILE} (${FAQ_ULA})" + log_write " ${COL_LIGHT_RED}${ip_address%/*}${COL_NC} does not match the IP found in ${PIHOLE_SETUP_VARS_FILE} (${FAQ_ULA})" fi else @@ -385,10 +475,10 @@ does_ip_match_setup_vars() { # since it exists in the setupVars.conf that way if [[ "${ip_address}" == "${setup_vars_ip}" ]]; then # show in green if it matches - log_write " ${COL_LIGHT_GREEN}${ip_address}${COL_NC} matches the IP found in ${VARSFILE}" + log_write " ${COL_LIGHT_GREEN}${ip_address}${COL_NC} matches the IP found in ${PIHOLE_SETUP_VARS_FILE}" else # otherwise show it in red - log_write " ${COL_LIGHT_RED}${ip_address}${COL_NC} does not match the IP found in ${VARSFILE} (${FAQ_ULA})" + log_write " ${COL_LIGHT_RED}${ip_address}${COL_NC} does not match the IP found in ${PIHOLE_SETUP_VARS_FILE} (${FAQ_ULA})" fi fi } @@ -423,7 +513,7 @@ detect_ip_addresses() { if [[ "${protocol}" == "6" ]]; then # let the user know that as long as there is one green address, things should be ok log_write " ^ Please note that you may have more than one IP address listed." - log_write " As long as one of them is green, and it matches what is in ${VARSFILE}, there is no need for concern.\n" + log_write " As long as one of them is green, and it matches what is in ${PIHOLE_SETUP_VARS_FILE}, there is no need for concern.\n" log_write " The link to the FAQ is for an issue that sometimes occurs when the IPv6 address changes, which is why we check for it.\n" fi } @@ -616,7 +706,7 @@ dig_at() { # Find a random blocked url that has not been whitelisted. # This helps emulate queries to different domains that a user might query # It will also give extra assurance that Pi-hole is correctly resolving and blocking domains - local random_url=$(shuf -n 1 "${GRAVITYFILE}" | awk -F ' ' '{ print $2 }') + local random_url=$(shuf -n 1 "${PIHOLE_BLOCKLIST_FILE}" | awk -F ' ' '{ print $2 }') # First, do a dig on localhost to see if Pi-hole can use itself to block a domain if local_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then @@ -783,22 +873,22 @@ show_content_of_files_in_dir() { show_content_of_pihole_files() { # Show the content of the files in /etc/dnsmasq.d - show_content_of_files_in_dir "${DNSMASQCONFDIR}" + show_content_of_files_in_dir "${DNSMASQ_D_DIRECTORY}" # Show the content of the files in /etc/lighttpd show_content_of_files_in_dir "/etc/lighttpd" # Show the content of the files in /etc/lighttpd show_content_of_files_in_dir "/etc/cron.d" # Show the content of the files in /var/www/html - # show_content_of_files_in_dir "${ADMINGITDIR}" + # show_content_of_files_in_dir "${WEB_GIT_DIRECTORY}" } analyze_gravity_list() { echo_current_diagnostic "Gravity list" # It's helpful to know how big a user's gravity file is - gravity_length=$(grep -c ^ "${GRAVITYFILE}") && \ - log_write "${INFO} ${GRAVITYFILE} is ${gravity_length} lines long." || \ + gravity_length=$(grep -c ^ "${PIHOLE_BLOCKLIST_FILE}") && \ + log_write "${INFO} ${PIHOLE_BLOCKLIST_FILE} is ${gravity_length} lines long." || \ # If the previous command failed, something is wrong with the file - log_write "${CROSS} ${COL_LIGHT_RED}${GRAVITYFILE} not found!${COL_NC}" + log_write "${CROSS} ${COL_LIGHT_RED}${PIHOLE_BLOCKLIST_FILE} not found!${COL_NC}" } tricorder_use_nc_or_ssl() { @@ -808,20 +898,20 @@ tricorder_use_nc_or_ssl() { # If the command exists, log_write " * Using ${COL_LIGHT_GREEN}openssl${COL_NC} for transmission." # encrypt and transmit the log and store the token returned in a variable - tricorder_token=$(cat ${DEBUG_LOG} | openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null) + tricorder_token=$(cat ${PIHOLE_DEBUG_LOG} | openssl s_client -quiet -connect tricorder.pi-hole.net:${TRICORDER_SSL_PORT_NUMBER} 2> /dev/null) # Otherwise, else # use net cat log_write "${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." - tricorder_token=$(cat ${DEBUG_LOG} | nc tricorder.pi-hole.net 9999) + tricorder_token=$(cat ${PIHOLE_DEBUG_LOG} | nc tricorder.pi-hole.net ${TRICORDER_NC_PORT_NUMBER}) fi } upload_to_tricorder() { # Set the permissions and owner - chmod 644 ${DEBUG_LOG} - chown "$USER":pihole ${DEBUG_LOG} + chmod 644 ${PIHOLE_DEBUG_LOG} + chown "$USER":pihole ${PIHOLE_DEBUG_LOG} # Let the user know debugging is complete echo "" @@ -829,7 +919,7 @@ upload_to_tricorder() { # Provide information on what they should do with their token log_write " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." - log_write " * For more information, see: ${COL_CYAN}https://pi-hole.net/2016/11/07/crack-our-medical-tricorder-win-a-raspberry-pi-3/${COL_NC}" + log_write " * For more information, see: ${TRICORDER_CONTEST}" log_write " * If available, we'll use openssl to upload the log, otherwise it will fall back to netcat." # If pihole -d is running automatically (usually throught the dashboard) if [[ "${AUTOMATED}" ]]; then @@ -838,10 +928,10 @@ upload_to_tricorder() { # and then decide again which tool to use to submit it if command -v openssl &> /dev/null; then log_write "${INFO} Using ${COL_LIGHT_GREEN}openssl${COL_NC} for transmission." - tricorder_token=$(openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin) + tricorder_token=$(openssl s_client -quiet -connect tricorder.pi-hole.net:${TRICORDER_SSL_PORT_NUMBER} 2> /dev/null < /dev/stdin) else log_write "${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." - tricorder_token=$(nc tricorder.pi-hole.net 9999 < /dev/stdin) + tricorder_token=$(nc tricorder.pi-hole.net ${TRICORDER_NC_PORT_NUMBER} < /dev/stdin) fi else echo "" @@ -864,13 +954,13 @@ upload_to_tricorder() { log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" log_write "" log_write " * Provide this token to the Pi-hole team for assistance at" - log_write " * ${COL_CYAN}https://discourse.pi-hole.net${COL_NC}" + log_write " * ${FORUMS_URL}" log_write " * Your log will self-destruct on our server after ${COL_LIGHT_RED}48 hours${COL_NC}." else log_write "${CROSS} ${COL_LIGHT_RED}There was an error uploading your debug log.${COL_NC}" log_write " * Please try again or contact the Pi-hole team for assistance." fi - log_write " * A local copy of the debug log can be found at: ${COL_CYAN}${DEBUG_LOG}${COL_NC}\n" + log_write " * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG}${COL_NC}\n" } # Run through all the functions we made From e10182c839b0d9b560b043332410f547e11845b6 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 10 Jun 2017 12:27:05 -0500 Subject: [PATCH 076/162] only parse files required by Pi-hole --- advanced/Scripts/piholeDebug.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index fe2bf36b..b3fdfce1 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -854,10 +854,17 @@ list_files_in_dir() { # If it's a directoy, do nothing : else - # Othwerise, display the filename - log_write "\n${COL_LIGHT_GREEN}$(ls -ld ${dir_to_parse}/${each_file})${COL_NC}" # Then, parse the file's content into an array so each line can be analyzed if need be - make_array_from_file "${dir_to_parse}/${each_file}" + for i in "${!REQUIRED_FILES[@]}"; do + if [[ "${dir_to_parse}/${each_file}" == ${REQUIRED_FILES[$i]} ]]; then + # display the filename + log_write "\n${COL_LIGHT_GREEN}$(ls -ld ${dir_to_parse}/${each_file})${COL_NC}" + # and parse the file into an array in case we ever need to analyze it line-by-line + make_array_from_file "${dir_to_parse}/${each_file}" + else + : + fi + done fi done } From b0cc1a38c3a2786cc72b1354ed67ac898c799f51 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 10 Jun 2017 15:28:04 -0500 Subject: [PATCH 077/162] adjust minor formatting for better readability --- advanced/Scripts/piholeDebug.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index b3fdfce1..c754f4b1 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -921,8 +921,10 @@ upload_to_tricorder() { chown "$USER":pihole ${PIHOLE_DEBUG_LOG} # Let the user know debugging is complete - echo "" - log_write "${TICK} ${COL_LIGHT_GREEN}** Finished debugging! **${COL_NC}\n" + log_write "" + log_write "${COL_LIGHT_PURPLE}********************************************${COL_NC}" + log_write "${COL_LIGHT_PURPLE}********************************************${COL_NC}" + log_write "${TICK} ${COL_LIGHT_GREEN}** FINISHED DEBUGGING! **${COL_NC}\n" # Provide information on what they should do with their token log_write " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." @@ -955,12 +957,14 @@ upload_to_tricorder() { # Check if tricorder.pi-hole.net is reachable and provide token # along with some additional useful information if [[ -n "${tricorder_token}" ]]; then - echo "" + log_write "" + log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" log_write "${TICK} Your debug token is: ${COL_LIGHT_GREEN}${tricorder_token}${COL_NC}" log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" + log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" log_write "" - log_write " * Provide this token to the Pi-hole team for assistance at" + log_write " * Provide the token above to the Pi-hole team for assistance at" log_write " * ${FORUMS_URL}" log_write " * Your log will self-destruct on our server after ${COL_LIGHT_RED}48 hours${COL_NC}." else From 3275c5f7109554ebfb5c6bb8771779b662cd905f Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 10 Jun 2017 15:54:27 -0500 Subject: [PATCH 078/162] more comments to help understand the script --- advanced/Scripts/piholeDebug.sh | 78 ++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index c754f4b1..3a2f9803 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -110,8 +110,10 @@ PIHOLE_WEB_SERVER_ERROR_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/error.log" # We can loop through the array at any time to see if it matches a value SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS") -# In a similar fashion, these are the folders Pi-hole needs -# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684 +# Store Pi-hole's processes in an array for easy use and parsing +PIHOLE_PROCESSES=( dnsmasq lighttpd pihole-FTL ) + +# Store the required directories in an array so it can be parsed through REQUIRED_DIRECTORIES=(${CORE_GIT_DIRECTORY} ${CRON_D_DIRECTORY} ${DNSMASQ_D_DIRECTORY} @@ -126,8 +128,7 @@ ${HTML_DIRECTORY} ${WEB_GIT_DIRECTORY} ${BLOCK_PAGE_DIRECTORY}) -# These are the files Pi-hole needs--also stored in array for parsing through -# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684 +# Store the required directories in an array so it can be parsed through REQUIRED_FILES=(${PIHOLE_CRON_FILE} ${PIHOLE_DNS_CONFIG_FILE} ${PIHOLE_DHCP_CONFIG_FILE} @@ -167,12 +168,13 @@ source_setup_variables() { } make_temporary_log() { - # Create temporary file for log + # Create a random temporary file for the log TEMPLOG=$(mktemp /tmp/pihole_temp.XXXXXX) # Open handle 3 for templog # https://stackoverflow.com/questions/18460186/writing-outputs-to-log-file-and-console exec 3>"$TEMPLOG" - # Delete templog, but allow for addressing via file handle. + # Delete templog, but allow for addressing via file handle + # This lets us write to the log without having a temporary file on the drive rm "$TEMPLOG" } @@ -254,6 +256,7 @@ compare_local_version_to_git_version() { # We need to search for "Pi-hole" when using pihole -v local search_term="Pi-hole" elif [[ "${pihole_component}" == "Web" ]]; then + # We need to search for "AdminLTE" so store it in a variable as well local search_term="AdminLTE" fi # Display what we are checking @@ -332,8 +335,10 @@ check_component_versions() { get_program_version() { local program_name="${1}" + # Create a loval variable so this function can be safely reused local program_version echo_current_diagnostic "${program_name} version" + # Evalutate the program we are checking, if it is any of the ones below, show the version case "${program_name}" in "lighttpd") program_version="$(${program_name} -v |& head -n1 | cut -d '/' -f2 | cut -d ' ' -f1)" ;; @@ -341,9 +346,10 @@ get_program_version() { ;; "php") program_version="$(${program_name} -v |& head -n1 | cut -d '-' -f1 | cut -d ' ' -f2)" ;; + # If a match is not found, show an error *) echo "Unrecognized program"; esac - # If the Web server does not have a version (the variable is empty) + # If the program does not have a version (the variable is empty) if [[ -z "${program_version}" ]]; then # Display and error log_write "${CROSS} ${COL_LIGHT_RED}${program_name} version could not be detected.${COL_NC}" @@ -364,13 +370,17 @@ check_critical_program_versions() { is_os_supported() { local os_to_check="${1}" + # Strip just the base name of the system using sed the_os=$(echo ${os_to_check} | sed 's/ .*//') + # If the variable is one of our supported OSes, case "${the_os}" in + # Print it in green "Raspbian") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; "Ubuntu") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; "Fedora") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; "Debian") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; "CentOS") log_write "${TICK} ${COL_LIGHT_GREEN}${os_to_check}${COL_NC}";; + # If not, show it in red and link to our software requirements page *) log_write "${CROSS} ${COL_LIGHT_RED}${os_to_check}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS})"; esac } @@ -447,8 +457,11 @@ processor_check() { parse_setup_vars() { echo_current_diagnostic "Setup variables" + # If the file exists, if_file_exists "${PIHOLE_SETUP_VARS_FILE}" && \ + # parse it parse_file "${PIHOLE_SETUP_VARS_FILE}" || \ + # If not, show an error log_write "${CROSS} ${COL_LIGHT_RED}Could not read ${PIHOLE_SETUP_VARS_FILE}.${COL_NC}" } @@ -461,7 +474,7 @@ does_ip_match_setup_vars() { local setup_vars_ip=$(cat ${PIHOLE_SETUP_VARS_FILE} | grep IPV${protocol}_ADDRESS | cut -d '=' -f2) # If it's an IPv6 address if [[ "${protocol}" == "6" ]]; then - # Strip off the / + # Strip off the / (CIDR notation) if [[ "${ip_address%/*}" == "${setup_vars_ip}" ]]; then # if it matches, show it in green log_write " ${COL_LIGHT_GREEN}${ip_address%/*}${COL_NC} matches the IP found in ${PIHOLE_SETUP_VARS_FILE}" @@ -501,8 +514,8 @@ detect_ip_addresses() { for i in "${!ip_addr_list[@]}"; do # For each one in the list, print it out does_ip_match_setup_vars "${protocol}" "${ip_addr_list[$i]}" - # log_write " ${ip_addr_list[$i]}" done + # Print a blank line just for formatting log_write "" else # If there are no IPs detected, explain that the protocol is not configured @@ -568,6 +581,7 @@ ping_gateway() { ping_internet() { local protocol="${1}" + # Ping a public address using the protocol passed as an argument ping_ipv4_or_ipv6 "${protocol}" log_write "* Checking Internet connectivity via IPv${protocol}..." # Try to ping the address 3 times @@ -584,6 +598,7 @@ ping_internet() { compare_port_to_service_assigned() { local service_name="${1}" + # The programs we use may change at some point, so they are in a varible here local resolver="dnsmasq" local web_server="lighttpd" local ftl="pihole-FT" @@ -624,6 +639,7 @@ check_required_ports() { ;; 4711) compare_port_to_service_assigned "${ftl}" ;; + # If it's not a default port that Pi-hole needs, just print it out for the user to see *) log_write "[${port_number}] is in use by ${service_name}"; esac done @@ -679,6 +695,7 @@ dig_at() { local IP="${2}" echo_current_diagnostic "Name resolution (IPv${protocol}) using a random blocked domain and a known ad-serving domain" # Set more local variables + # We need to test name resolution locally, via Pi-hole, and via a public resolver local url local local_dig local pihole_dig @@ -745,13 +762,11 @@ dig_at() { process_status(){ # Check to make sure Pi-hole's services are running and active echo_current_diagnostic "Pi-hole processes" - # Store them in an array for easy use - PROCESSES=( dnsmasq lighttpd pihole-FTL ) # Local iterator local i # For each process, - for i in "${PROCESSES[@]}"; do - # get its status + for i in "${PIHOLE_PROCESSES=[@]}"; do + # get its status via systemctl local status_of_process=$(systemctl is-active "${i}") # and print it out to the user if [[ "${status_of_process}" == "active" ]]; then @@ -766,6 +781,7 @@ process_status(){ make_array_from_file() { local filename="${1}" + # Set the array to be empty so we can start fresh when the function is used local file_content=() # If the file is a directory if [[ -d "${filename}" ]]; then @@ -785,7 +801,10 @@ make_array_from_file() { : fi done < "${filename}" + # Now the we have made an array of the file's content for each_line in "${file_content[@]}"; do + # Print each line + # At some point, we may want to check the file line-by-line, so that's the reason for an array log_write " ${each_line}" done fi @@ -862,6 +881,7 @@ list_files_in_dir() { # and parse the file into an array in case we ever need to analyze it line-by-line make_array_from_file "${dir_to_parse}/${each_file}" else + # Otherwise, do nothing since it's not a file needed for Pi-hole so we don't care about it : fi done @@ -879,14 +899,10 @@ show_content_of_files_in_dir() { } show_content_of_pihole_files() { - # Show the content of the files in /etc/dnsmasq.d + # Show the content of the files in each of Pi-hole's folders show_content_of_files_in_dir "${DNSMASQ_D_DIRECTORY}" - # Show the content of the files in /etc/lighttpd - show_content_of_files_in_dir "/etc/lighttpd" - # Show the content of the files in /etc/lighttpd - show_content_of_files_in_dir "/etc/cron.d" - # Show the content of the files in /var/www/html - # show_content_of_files_in_dir "${WEB_GIT_DIRECTORY}" + show_content_of_files_in_dir "${WEB_SERVER_CONFIG_DIRECTORY}" + show_content_of_files_in_dir "${CRON_D_DIRECTORY}" } analyze_gravity_list() { @@ -910,17 +926,19 @@ tricorder_use_nc_or_ssl() { else # use net cat log_write "${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." + # Save the token returned by our server in a variable tricorder_token=$(cat ${PIHOLE_DEBUG_LOG} | nc tricorder.pi-hole.net ${TRICORDER_NC_PORT_NUMBER}) fi } upload_to_tricorder() { + local username="pihole" # Set the permissions and owner chmod 644 ${PIHOLE_DEBUG_LOG} - chown "$USER":pihole ${PIHOLE_DEBUG_LOG} + chown "$USER":"${username}" ${PIHOLE_DEBUG_LOG} - # Let the user know debugging is complete + # Let the user know debugging is complete with something strikingly visual log_write "" log_write "${COL_LIGHT_PURPLE}********************************************${COL_NC}" log_write "${COL_LIGHT_PURPLE}********************************************${COL_NC}" @@ -936,16 +954,21 @@ upload_to_tricorder() { log_write "${INFO} Debug script running in automated mode" # and then decide again which tool to use to submit it if command -v openssl &> /dev/null; then + # If openssl is available, use it log_write "${INFO} Using ${COL_LIGHT_GREEN}openssl${COL_NC} for transmission." + # Save the token returned by our server in a variable tricorder_token=$(openssl s_client -quiet -connect tricorder.pi-hole.net:${TRICORDER_SSL_PORT_NUMBER} 2> /dev/null < /dev/stdin) else + # Otherwise, fallback to netcat log_write "${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission." + # Save the token returned by our server in a variable tricorder_token=$(nc tricorder.pi-hole.net ${TRICORDER_NC_PORT_NUMBER} < /dev/stdin) fi + # If we're not running in automated mode, else echo "" - # Give the user a choice of uploading it or not - # Users can review the log file locally and try to self-diagnose their problem + # give the user a choice of uploading it or not + # Users can review the log file locally (or the output of the script since they are the same) and try to self-diagnose their problem read -r -p "[?] Would you like to upload the log? [y/N] " response case ${response} in # If they say yes, run our function for uploading the log @@ -957,6 +980,8 @@ upload_to_tricorder() { # Check if tricorder.pi-hole.net is reachable and provide token # along with some additional useful information if [[ -n "${tricorder_token}" ]]; then + # Again, try to make this visually striking so the user realizes they need to do something with this information + # Namely, provide the Pi-hole devs with the token log_write "" log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" log_write "${COL_LIGHT_PURPLE}***********************************${COL_NC}" @@ -967,10 +992,13 @@ upload_to_tricorder() { log_write " * Provide the token above to the Pi-hole team for assistance at" log_write " * ${FORUMS_URL}" log_write " * Your log will self-destruct on our server after ${COL_LIGHT_RED}48 hours${COL_NC}." - else + # If no token was generated + else + # Show an error and some help instructions log_write "${CROSS} ${COL_LIGHT_RED}There was an error uploading your debug log.${COL_NC}" log_write " * Please try again or contact the Pi-hole team for assistance." fi + # Finally, show where the log file is no matter the outcome of the function so users can look at it log_write " * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG}${COL_NC}\n" } From 881819ed5fda3c8c7f581f90bee3a782bcb02d38 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 10 Jun 2017 18:37:28 -0500 Subject: [PATCH 079/162] ignore big files we dont need to know about; also fix diagnosing pihole processes --- advanced/Scripts/piholeDebug.sh | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 3a2f9803..7fb63b65 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -80,6 +80,7 @@ PIHOLE_DHCP_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/02-pihole-dhcp.conf" PIHOLE_WILDCARD_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/03-wildcard.conf" WEB_SERVER_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/lighttpd.conf" +WEB_SERVER_CUSTOM_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/external.conf" PIHOLE_DEFAULT_AD_LISTS="${PIHOLE_DIRECTORY}/adlists.default" PIHOLE_USER_DEFINED_AD_LISTS="${PIHOLE_DIRECTORY}/adlists.list" @@ -111,7 +112,7 @@ PIHOLE_WEB_SERVER_ERROR_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/error.log" SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS") # Store Pi-hole's processes in an array for easy use and parsing -PIHOLE_PROCESSES=( dnsmasq lighttpd pihole-FTL ) +PIHOLE_PROCESSES=( "dnsmasq" "lighttpd" "pihole-FTL" ) # Store the required directories in an array so it can be parsed through REQUIRED_DIRECTORIES=(${CORE_GIT_DIRECTORY} @@ -765,7 +766,7 @@ process_status(){ # Local iterator local i # For each process, - for i in "${PIHOLE_PROCESSES=[@]}"; do + for i in "${PIHOLE_PROCESSES[@]}"; do # get its status via systemctl local status_of_process=$(systemctl is-active "${i}") # and print it out to the user @@ -872,6 +873,16 @@ list_files_in_dir() { if [[ -d "${each_file}" ]]; then # If it's a directoy, do nothing : + elif [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_BLOCKLIST_FILE}" ]] || \ + [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_FTL_LOG}" ]] || \ + [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_DEBUG_LOG}" ]] || \ + [[ ${dir_to_parse}/${each_file} == ${PIHOLE_RAW_BLOCKLIST_FILES} ]] || \ + [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_INSTALL_LOG_FILE}" ]] || \ + [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_SETUP_VARS_FILE}" ]] || \ + [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG}" ]] || \ + [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}" ]] || \ + [[ ${dir_to_parse}/${each_file} == ${PIHOLE_LOG_GZIPS} ]]; then + : else # Then, parse the file's content into an array so each line can be analyzed if need be for i in "${!REQUIRED_FILES[@]}"; do @@ -900,9 +911,11 @@ show_content_of_files_in_dir() { show_content_of_pihole_files() { # Show the content of the files in each of Pi-hole's folders + show_content_of_files_in_dir "${PIHOLE_DIRECTORY}" show_content_of_files_in_dir "${DNSMASQ_D_DIRECTORY}" show_content_of_files_in_dir "${WEB_SERVER_CONFIG_DIRECTORY}" show_content_of_files_in_dir "${CRON_D_DIRECTORY}" + show_content_of_files_in_dir "${WEB_SERVER_LOG_DIRECTORY}" } analyze_gravity_list() { From 6d10a498a5178fa1060e333bf5159fbd3596d94f Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 10 Jun 2017 21:57:17 -0500 Subject: [PATCH 080/162] implement a limit on how many lines of a file we want to view --- advanced/Scripts/piholeDebug.sh | 45 +++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 7fb63b65..103e9495 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -782,6 +782,11 @@ process_status(){ make_array_from_file() { local filename="${1}" + # The second argument can put a limit on how many line should be read from the file + # Since some of the files are so large, this is helpful to limit the output + local limit=${2} + # A local iterator for testing if we are at the limit above + local i=0 # Set the array to be empty so we can start fresh when the function is used local file_content=() # If the file is a directory @@ -791,7 +796,7 @@ make_array_from_file() { else # Otherwise, read the file line by line while IFS= read -r line;do - # Strip out comments and blank lines + # Othwerise, strip out comments and blank lines new_line=$(echo "${line}" | sed -e 's/#.*$//' -e '/^$/d') # If the line still has content (a non-zero value) if [[ -n "${new_line}" ]]; then @@ -801,14 +806,23 @@ make_array_from_file() { # Otherwise, it's a blank line or comment, so do nothing : fi + # Increment the iterator +1 + i=$((i+1)) + # but if the limit of lines we want to see is exceeded + if [[ -z ${limit} ]]; then + # do nothing + : + elif [[ $i -eq ${limit} ]]; then + break + fi done < "${filename}" - # Now the we have made an array of the file's content - for each_line in "${file_content[@]}"; do - # Print each line - # At some point, we may want to check the file line-by-line, so that's the reason for an array - log_write " ${each_line}" - done - fi + # Now the we have made an array of the file's content + for each_line in "${file_content[@]}"; do + # Print each line + # At some point, we may want to check the file line-by-line, so that's the reason for an array + log_write " ${each_line}" + done + fi } parse_file() { @@ -870,7 +884,7 @@ list_files_in_dir() { local files_found=( $(ls "${dir_to_parse}") ) # For each file in the array, for each_file in "${files_found[@]}"; do - if [[ -d "${each_file}" ]]; then + if [[ -d "${dir_to_parse}/${each_file}" ]]; then # If it's a directoy, do nothing : elif [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_BLOCKLIST_FILE}" ]] || \ @@ -889,8 +903,17 @@ list_files_in_dir() { if [[ "${dir_to_parse}/${each_file}" == ${REQUIRED_FILES[$i]} ]]; then # display the filename log_write "\n${COL_LIGHT_GREEN}$(ls -ld ${dir_to_parse}/${each_file})${COL_NC}" - # and parse the file into an array in case we ever need to analyze it line-by-line - make_array_from_file "${dir_to_parse}/${each_file}" + # Check if the file we want to view has a limit (because sometimes we just need a little bit of info from the file, not the entire thing) + case "${dir_to_parse}/${each_file}" in + # If it's Web server error log, just give the first 25 lines + "${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}") make_array_from_file "${dir_to_parse}/${each_file}" 25 + ;; + # Same for the FTL log + "${PIHOLE_FTL_LOG}") make_array_from_file "${dir_to_parse}/${each_file}" 25 + ;; + # parse the file into an array in case we ever need to analyze it line-by-line + *) make_array_from_file "${dir_to_parse}/${each_file}"; + esac else # Otherwise, do nothing since it's not a file needed for Pi-hole so we don't care about it : From 172b8d2427a34d88d04c5548c72c6fc99c1e9adb Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 10 Jun 2017 22:18:33 -0500 Subject: [PATCH 081/162] parse ftl log --- advanced/Scripts/piholeDebug.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 103e9495..8662422c 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -43,6 +43,7 @@ fi FAQ_UPDATE_PI_HOLE="${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC}" FAQ_CHECKOUT_COMMAND="${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC}" FAQ_HARDWARE_REQUIREMENTS="${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273${COL_NC}" +FAQ_HARDWARE_REQUIREMENTS_PORTS="${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC}" FAQ_GATEWAY="${COL_CYAN}https://discourse.pi-hole.net/t/why-is-a-default-gateway-important-for-pi-hole/3546${COL_NC}" FAQ_ULA="${COL_CYAN}https://discourse.pi-hole.net/t/use-ipv6-ula-addresses-for-pi-hole/2127${COL_NC}" FAQ_FTL_COMPATIBILITY="${COL_CYAN}https://github.com/pi-hole/FTL#compatibility-list${COL_NC}" @@ -609,7 +610,7 @@ compare_port_to_service_assigned() { # Otherwise, else # Show the service name in red since it's non-standard - log_write "[${COL_LIGHT_RED}${port_number}${COL_NC}] is in use by ${COL_LIGHT_RED}${service_name}${COL_NC} (${COL_CYAN}https://discourse.pi-hole.net/t/hardware-software-requirements/273#ports${COL_NC})" + log_write "[${COL_LIGHT_RED}${port_number}${COL_NC}] is in use by ${COL_LIGHT_RED}${service_name}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_PORTS})" fi } @@ -888,7 +889,6 @@ list_files_in_dir() { # If it's a directoy, do nothing : elif [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_BLOCKLIST_FILE}" ]] || \ - [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_FTL_LOG}" ]] || \ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_DEBUG_LOG}" ]] || \ [[ ${dir_to_parse}/${each_file} == ${PIHOLE_RAW_BLOCKLIST_FILES} ]] || \ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_INSTALL_LOG_FILE}" ]] || \ @@ -939,6 +939,7 @@ show_content_of_pihole_files() { show_content_of_files_in_dir "${WEB_SERVER_CONFIG_DIRECTORY}" show_content_of_files_in_dir "${CRON_D_DIRECTORY}" show_content_of_files_in_dir "${WEB_SERVER_LOG_DIRECTORY}" + show_content_of_files_in_dir "${LOG_DIRECTORY}" } analyze_gravity_list() { From fc0440546f95db37c3944ea40299f2e83235fe3e Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 10 Jun 2017 23:20:27 -0500 Subject: [PATCH 082/162] add functions to parse head and tails of gravity.list and pihole.log --- advanced/Scripts/piholeDebug.sh | 49 +++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 8662422c..d6526d9c 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -944,11 +944,49 @@ show_content_of_pihole_files() { analyze_gravity_list() { echo_current_diagnostic "Gravity list" - # It's helpful to know how big a user's gravity file is - gravity_length=$(grep -c ^ "${PIHOLE_BLOCKLIST_FILE}") && \ - log_write "${INFO} ${PIHOLE_BLOCKLIST_FILE} is ${gravity_length} lines long." || \ - # If the previous command failed, something is wrong with the file - log_write "${CROSS} ${COL_LIGHT_RED}${PIHOLE_BLOCKLIST_FILE} not found!${COL_NC}" + local head_line + local tail_line + # Put the current Internal Field Separator into another variable so it can be restored later + OLD_IFS="$IFS" + # Get the lines that are in the file(s) and store them in an array for parsing later + IFS=$'\r\n' + local gravity_permissions=$(ls -ld "${PIHOLE_BLOCKLIST_FILE}") + log_write "${COL_LIGHT_GREEN}${gravity_permissions}${COL_NC}" + local gravity_head=() + gravity_head=( $(head -n 4 ${PIHOLE_BLOCKLIST_FILE}) ) + log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_BLOCKLIST_FILE})------${COL_NC}" + for head_line in "${gravity_head[@]}"; do + log_write " ${head_line}" + done + log_write "" + local gravity_tail=() + gravity_tail=( $(tail -n 4 ${PIHOLE_BLOCKLIST_FILE}) ) + log_write " ${COL_CYAN}-----tail of $(basename ${PIHOLE_BLOCKLIST_FILE})------${COL_NC}" + for tail_line in "${gravity_tail[@]}"; do + log_write " ${tail_line}" + done + # Set the IFS back to what it was + IFS="$OLD_IFS" +} + +analyze_pihole_log() { + echo_current_diagnostic "Pi-hole log" + local head_line + # Put the current Internal Field Separator into another variable so it can be restored later + OLD_IFS="$IFS" + # Get the lines that are in the file(s) and store them in an array for parsing later + IFS=$'\r\n' + local pihole_log_permissions=$(ls -ld "${PIHOLE_LOG}") + log_write "${COL_LIGHT_GREEN}${pihole_log_permissions}${COL_NC}" + local pihole_log_head=() + pihole_log_head=( $(head -n 20 ${PIHOLE_LOG}) ) + log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_LOG})------${COL_NC}" + for head_line in "${pihole_log_head[@]}"; do + log_write " ${head_line}" + done + log_write "" + # Set the IFS back to what it was + IFS="$OLD_IFS" } tricorder_use_nc_or_ssl() { @@ -1056,5 +1094,6 @@ parse_setup_vars check_x_headers analyze_gravity_list show_content_of_pihole_files +analyze_pihole_log copy_to_debug_log upload_to_tricorder From aff5ff08d55b3a46bf98e0ca649f25895a4211ca Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Thu, 15 Jun 2017 17:50:05 +1000 Subject: [PATCH 083/162] Trim version output when update is successful (#1527) --- advanced/Scripts/update.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/advanced/Scripts/update.sh b/advanced/Scripts/update.sh index 24b30de4..6aef183b 100755 --- a/advanced/Scripts/update.sh +++ b/advanced/Scripts/update.sh @@ -197,21 +197,21 @@ main() { if [[ "${web_update}" == true ]]; then web_version_current="$(/usr/local/bin/pihole version --admin --current)" echo ":::" - echo "::: Web Admin version is now at ${web_version_current}" + echo "::: Web Admin version is now at ${web_version_current/* v/v}}" echo "::: If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'" fi if [[ "${core_update}" == true ]]; then pihole_version_current="$(/usr/local/bin/pihole version --pihole --current)" echo ":::" - echo "::: Pi-hole version is now at ${pihole_version_current}" + echo "::: Pi-hole version is now at ${pihole_version_current/* v/v}}" echo "::: If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'" fi if [[ ${FTL_update} == true ]]; then - FTL_version_current="$(/usr/bin/pihole-FTL tag)" + FTL_version_current="$(/usr/local/bin/pihole version --ftl --current)" echo ":::" - echo "::: FTL version is now at ${FTL_version_current}" + echo "::: FTL version is now at ${FTL_version_current/* v/v}}" start_service pihole-FTL enable_service pihole-FTL fi From 54a88ab5ab7fcc1ec440677ed9a6eec67d52fa23 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 17 Jun 2017 08:43:05 +0200 Subject: [PATCH 084/162] Change ownership of /etc/pihole to user/group pihole. Fixes #1529 (#1530) --- advanced/pihole-FTL.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced/pihole-FTL.service b/advanced/pihole-FTL.service index 30cd140f..627fad8c 100644 --- a/advanced/pihole-FTL.service +++ b/advanced/pihole-FTL.service @@ -26,7 +26,7 @@ start() { echo "pihole-FTL is already running" else touch /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port - chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port + chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /etc/pihole chmod 0644 /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port su -s /bin/sh -c "/usr/bin/pihole-FTL" "$FTLUSER" echo From 3d7582faec8232e15dccf94909fc1416794915f3 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 17 Jun 2017 08:54:26 +0200 Subject: [PATCH 085/162] Delete temporary files after installing the FTL binary. Fixes #1525 --- automated install/basic-install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index e8b28f62..053e04ba 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -1277,6 +1277,7 @@ FTLinstall() { echo -n "transferred... " stop_service pihole-FTL &> /dev/null install -T -m 0755 /tmp/${binary} /usr/bin/pihole-FTL + rm /tmp/${binary} /tmp/${binary}.sha1 cd "${orig_dir}" install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/pihole-FTL.service" "/etc/init.d/pihole-FTL" echo "done." From b32096b16e3a7d81f44752cf41547d98a315b61c Mon Sep 17 00:00:00 2001 From: Dan Schaper Date: Sat, 17 Jun 2017 03:59:27 -0700 Subject: [PATCH 086/162] Change from admin to approvers teams --- .pullapprove.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pullapprove.yml b/.pullapprove.yml index 39566b34..6beb4d34 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -35,4 +35,4 @@ groups: - master required: 4 teams: - - admin + - approvers From 0283a1ab74f7a404b96cf28fd055e5077f9b248d Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 17 Jun 2017 13:50:10 +0200 Subject: [PATCH 087/162] Introduce new file black.list for blacklist content --- advanced/01-pihole.conf | 1 + gravity.sh | 57 ++++++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/advanced/01-pihole.conf b/advanced/01-pihole.conf index 1b157f88..79735c15 100644 --- a/advanced/01-pihole.conf +++ b/advanced/01-pihole.conf @@ -22,6 +22,7 @@ addn-hosts=/etc/pihole/gravity.list addn-hosts=/etc/pihole/local.list +addn-hosts=/etc/pihole/black.list domain-needed diff --git a/gravity.sh b/gravity.sh index a5231d5e..cb6768e4 100755 --- a/gravity.sh +++ b/gravity.sh @@ -54,6 +54,7 @@ IPV6_ADDRESS=${IPV6_ADDRESS} basename=pihole piholeDir=/etc/${basename} adList=${piholeDir}/gravity.list +blackList=${piholeDir}/black.list localList=${piholeDir}/local.list justDomainsExtension=domains matterAndLight=${basename}.0.matterandlight.txt @@ -236,7 +237,7 @@ gravity_Blacklist() { numBlacklisted=$(wc -l < "${blacklistFile}") plural=; [[ "$numBlacklisted" != "1" ]] && plural=s echo -n "::: Blacklisting $numBlacklisted domain${plural}..." - cat ${blacklistFile} >> ${piholeDir}/${eventHorizon} + cat "${blacklistFile}" > "${blackList}.tmp" echo " done!" else echo "::: Nothing to blacklist!" @@ -299,6 +300,23 @@ gravity_unique() { echo "::: $numberOf unique domains trapped in the event horizon." } +gravity_doHostFormat() { + # 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 "${1}" | awk -v ipv4addr="$IPV4_ADDRESS" -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> "${2}" + elif [[ -n "${IPV4_ADDRESS}" && -z "${IPV6_ADDRESS}" ]];then + # Only IPv4 + cat "${1}" | awk -v ipv4addr="$IPV4_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0}' >> "${2}" + elif [[ -z "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then + # Only IPv6 + cat "${1}" | awk -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv6addr" "$0}' >> "${2}" + 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 +} + gravity_hostFormat() { # Format domain list as "192.168.x.x domain.com" echo -n "::: Formatting domains into a HOSTS file..." @@ -310,32 +328,23 @@ gravity_hostFormat() { else echo "::: Error: Unable to determine fully qualified domain name of host" fi - # Check vars from setupVars.conf to see if we're using IPv4, IPv6, Or both. - if [[ -n "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then - echo -e "${IPV4_ADDRESS} ${hostname}\n${IPV6_ADDRESS} ${hostname}\n${IPV4_ADDRESS} pi.hole\n${IPV6_ADDRESS} pi.hole" > ${localList} - # 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 - - echo -e "${IPV4_ADDRESS} ${hostname}\n${IPV4_ADDRESS} pi.hole" > ${localList} - # 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 - - echo -e "${IPV6_ADDRESS} ${hostname}\n${IPV6_ADDRESS} pi.hole" > ${localList} - # 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 + echo -e "${hostname}\npi.hole" > "${localList}.tmp" + # Copy the file over as /etc/pihole/local.list so dnsmasq can use it + gravity_doHostFormat "${localList}.tmp" "${localList}" + rm "${localList}.tmp" + echo "" > "${piholeDir}/${accretionDisc}" + gravity_doHostFormat "${piholeDir}/${eventHorizon}" "${piholeDir}/${accretionDisc}" # Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it - cp ${piholeDir}/${accretionDisc} ${adList} + cp "${piholeDir}/${accretionDisc}" "${adList}" + rm "${piholeDir}/${accretionDisc}" + + echo -e "" > "${blackList}.tmp" + gravity_doHostFormat "${blackList}.tmp" "${blackList}" + # Copy the file over as /etc/pihole/black.list so dnsmasq can use it + cp "${blackList}.tmp" "${blackList}" + rm "${blackList}.tmp" echo " done!" } From 0a9c2341272d45dd8b161a24d23cc5fe36a50d0c Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 17 Jun 2017 13:57:27 +0200 Subject: [PATCH 088/162] Add "pihole -g -b" to *only* update black.list (saves a bunch of time when adding/changing only blacklisted files - won'tdownload lal lists, but only processes the blacklist and restars dnsmasq) --- gravity.sh | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/gravity.sh b/gravity.sh index cb6768e4..2b860183 100755 --- a/gravity.sh +++ b/gravity.sh @@ -317,9 +317,8 @@ gravity_doHostFormat() { fi } -gravity_hostFormat() { +gravity_hostFormatLocal() { # Format domain list as "192.168.x.x domain.com" - echo -n "::: Formatting domains into a HOSTS file..." if [[ -f /etc/hostname ]]; then hostname=$( "${piholeDir}/${accretionDisc}" gravity_doHostFormat "${piholeDir}/${eventHorizon}" "${piholeDir}/${accretionDisc}" # Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it cp "${piholeDir}/${accretionDisc}" "${adList}" rm "${piholeDir}/${accretionDisc}" +} +gravity_hostFormatBlack() { + # Format domain list as "192.168.x.x domain.com" echo -e "" > "${blackList}.tmp" gravity_doHostFormat "${blackList}.tmp" "${blackList}" # Copy the file over as /etc/pihole/black.list so dnsmasq can use it cp "${blackList}.tmp" "${blackList}" rm "${blackList}.tmp" - echo " done!" } # blackbody - remove any remnant files from script processes @@ -386,11 +390,6 @@ gravity_advanced() { } gravity_reload() { - #Clear no longer needed files... - echo ":::" - echo -n "::: Cleaning up un-needed files..." - rm ${piholeDir}/pihole.*.txt - echo " done!" # Reload hosts file echo ":::" @@ -411,6 +410,7 @@ for var in "$@"; do "-f" | "--force" ) forceGrav=true;; "-h" | "--help" ) helpFunc;; "-sd" | "--skip-download" ) skipDownload=true;; + "-b" | "--blacklist-only" ) blackListOnly=true;; esac done @@ -420,22 +420,39 @@ if [[ "${forceGrav}" == true ]]; then echo " done!" fi -gravity_collapse -gravity_spinup -if [[ "${skipDownload}" == false ]]; then +if [[ ! "${blackListOnly}" == true ]]; then + gravity_collapse + gravity_spinup + if [[ "${skipDownload}" == false ]]; then gravity_Schwarzchild gravity_advanced -else + else echo "::: Using cached Event Horizon list..." numberOf=$(wc -l < ${piholeDir}/${preEventHorizon}) - echo "::: $numberOf unique domains trapped in the event horizon." + echo "::: $numberOf unique domains trapped in the event horizon." + fi + gravity_Whitelist fi -gravity_Whitelist gravity_Blacklist gravity_Wildcard -gravity_hostFormat +echo -n "::: Formatting domains into a HOSTS file..." +if [[ ! "${blackListOnly}" == true ]]; then + gravity_hostFormatLocal + gravity_hostFormatGravity +fi +gravity_hostFormatBlack +echo " done!" + gravity_blackbody +if [[ ! "${blackListOnly}" == true ]]; then + #Clear no longer needed files... + echo ":::" + echo -n "::: Cleaning up un-needed files..." + rm ${piholeDir}/pihole.*.txt + echo " done!" +fi + gravity_reload "${PIHOLE_COMMAND}" status From 92e691408f58e6ae8fd3eae7acfcfd0175245abc Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 17 Jun 2017 14:14:07 +0200 Subject: [PATCH 089/162] Remove useless cat --- gravity.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gravity.sh b/gravity.sh index 2b860183..558cbd18 100755 --- a/gravity.sh +++ b/gravity.sh @@ -304,13 +304,13 @@ gravity_doHostFormat() { # 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 "${1}" | awk -v ipv4addr="$IPV4_ADDRESS" -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> "${2}" + awk -v ipv4addr="$IPV4_ADDRESS" -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> "${2}" < "${1}" elif [[ -n "${IPV4_ADDRESS}" && -z "${IPV6_ADDRESS}" ]];then # Only IPv4 - cat "${1}" | awk -v ipv4addr="$IPV4_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0}' >> "${2}" + awk -v ipv4addr="$IPV4_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0}' >> "${2}" < "${1}" elif [[ -z "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then # Only IPv6 - cat "${1}" | awk -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv6addr" "$0}' >> "${2}" + awk -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv6addr" "$0}' >> "${2}" < "${1}" 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 @@ -330,6 +330,7 @@ gravity_hostFormatLocal() { echo -e "${hostname}\npi.hole" > "${localList}.tmp" # Copy the file over as /etc/pihole/local.list so dnsmasq can use it + rm "${localList}" gravity_doHostFormat "${localList}.tmp" "${localList}" rm "${localList}.tmp" } From 8bad56e89799f05d64d30d367361e9814b48f03c Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 17 Jun 2017 14:24:30 +0200 Subject: [PATCH 090/162] Improve displayed messages and overall logic --- gravity.sh | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/gravity.sh b/gravity.sh index 558cbd18..f333b706 100755 --- a/gravity.sh +++ b/gravity.sh @@ -236,9 +236,7 @@ gravity_Blacklist() { if [[ -f "${blacklistFile}" ]]; then numBlacklisted=$(wc -l < "${blacklistFile}") plural=; [[ "$numBlacklisted" != "1" ]] && plural=s - echo -n "::: Blacklisting $numBlacklisted domain${plural}..." - cat "${blacklistFile}" > "${blackList}.tmp" - echo " done!" + echo "::: Exact blocked domain${plural}: $numBlacklisted" else echo "::: Nothing to blacklist!" fi @@ -345,12 +343,16 @@ gravity_hostFormatGravity() { } gravity_hostFormatBlack() { - # Format domain list as "192.168.x.x domain.com" - echo -e "" > "${blackList}.tmp" - gravity_doHostFormat "${blackList}.tmp" "${blackList}" - # Copy the file over as /etc/pihole/black.list so dnsmasq can use it - cp "${blackList}.tmp" "${blackList}" - rm "${blackList}.tmp" + if [[ -f "${blacklistFile}" ]]; then + numBlacklisted=$(wc -l < "${blacklistFile}") + # Format domain list as "192.168.x.x domain.com" + gravity_doHostFormat "${blacklistFile}" "${blackList}.tmp" + # Copy the file over as /etc/pihole/black.list so dnsmasq can use it + cp "${blackList}.tmp" "${blackList}" + rm "${blackList}.tmp" + else + echo "::: Nothing to blacklist!" + fi } # blackbody - remove any remnant files from script processes From e4cc5b3847314235f88953835fdbae2aea7adb70 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 17 Jun 2017 14:49:02 +0200 Subject: [PATCH 091/162] Disable black.list on "pihole disable" --- pihole | 1 + 1 file changed, 1 insertion(+) diff --git a/pihole b/pihole index f2bc7000..055d6bce 100755 --- a/pihole +++ b/pihole @@ -193,6 +193,7 @@ Time: elif [[ "${1}" == "0" ]]; then # Disable Pi-hole sed -i 's/^addn-hosts=\/etc\/pihole\/gravity.list/#addn-hosts=\/etc\/pihole\/gravity.list/' /etc/dnsmasq.d/01-pihole.conf + sed -i 's/^addn-hosts=\/etc\/pihole\/black.list/#addn-hosts=\/etc\/pihole\/black.list/' /etc/dnsmasq.d/01-pihole.conf if [[ -e "$wildcardlist" ]]; then mv "$wildcardlist" "/etc/pihole/wildcard.list" fi From 05798fe07a363bc1b25e89396efec74b3abc6ace Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 19 Jun 2017 20:21:47 +0200 Subject: [PATCH 092/162] cp + rm === mv (well, almost) --- gravity.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/gravity.sh b/gravity.sh index f333b706..285ce5c3 100755 --- a/gravity.sh +++ b/gravity.sh @@ -338,8 +338,7 @@ gravity_hostFormatGravity() { echo "" > "${piholeDir}/${accretionDisc}" gravity_doHostFormat "${piholeDir}/${eventHorizon}" "${piholeDir}/${accretionDisc}" # Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it - cp "${piholeDir}/${accretionDisc}" "${adList}" - rm "${piholeDir}/${accretionDisc}" + mv "${piholeDir}/${accretionDisc}" "${adList}" } gravity_hostFormatBlack() { @@ -348,8 +347,7 @@ gravity_hostFormatBlack() { # Format domain list as "192.168.x.x domain.com" gravity_doHostFormat "${blacklistFile}" "${blackList}.tmp" # Copy the file over as /etc/pihole/black.list so dnsmasq can use it - cp "${blackList}.tmp" "${blackList}" - rm "${blackList}.tmp" + mv "${blackList}.tmp" "${blackList}" else echo "::: Nothing to blacklist!" fi From 5b472ff67cb901b2bbb79d917ae8e6a2115a00f0 Mon Sep 17 00:00:00 2001 From: Terror Date: Tue, 20 Jun 2017 08:28:04 +1200 Subject: [PATCH 093/162] Add support for PowerPC architecture Related to https://github.com/pi-hole/FTL/pull/88 --- automated install/basic-install.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index c65ef49f..ade1a1d4 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -1265,6 +1265,10 @@ FTLdetect() { echo "::: Detected ARM architecture" binary="pihole-FTL-arm-linux-gnueabi" fi + elif [[ $machine == ppc ]]; then + # PowerPC + echo "::: Detected PowerPC architecture" + binary="pihole-FTL-powerpc-linux-gnu" elif [[ $machine == x86_64 ]]; then # 64bit echo "::: Detected x86_64 architecture" From ecde2225122904a89543712ec8f2b0fd1da26ff6 Mon Sep 17 00:00:00 2001 From: Adam Warner Date: Tue, 20 Jun 2017 22:17:41 +0100 Subject: [PATCH 094/162] [Staging] 3.1 (#1502) * Fix handling of wildcard help text * Rewrite help text for better handling of params * Replace misleading letter variable * stash changes on branch switch, else it fails if any changes have been made. * Make changes according to comment in #1384 * Update queryFunc() * Allow scanList() to search files using a wildcard by removing quotes wrapped around `${list}` * scanList() will not provide a domain ouput on each string if exact is specified (`grep -l`) * Remove unused processWildcards() function * Return a message if no domain is specified * IDN domains are converted to punycode when running a `pihole -q` search if the `python` package is available, otherwise will revert to current behaviour * Scan Blacklist & Wildcards first, exiting from search if a match is found (Fixes #1330) * Use one `grep` subshell to search for all "*.domains" lists at once (opposed to looping to get every matching file name, and then spawning a `grep` instance for every matching file) * queryFunc() will not return "(0 results)" output from files where no match is found * Sort results based off list number * Return a message if no results are found * Update basic-install.sh * Update block page. Allow for setupVars setting of CUSTOMBLOCKPAGE (bool) to prevent it being overwritten * simplify * further simplify * fix inteliJ IDEA complaints * even further simplify * tidy up output * revert line, looks tidyer * clarify * Revert "Ensure any changes to blocking page are updated." * We test for dpkg lock on line 830 directly, no need for the check also in the template section. Signed-off-by: Dan Schaper * Display FTL version & version.sh rewrite While testing to make sure `pihole -v` would output `pihole-FTL version`, I noticed some options didn't work how I expected them to. For example, if I use `pihole -v -p`, I would expect to see the version output of Pi-hole Core. Instead, I'm informed that it's an invalid option. I've had the following things in mind while rewriting this: * I'm operating under the assumption that FTL is only installed if the Admin Console is (Line 113 exit 0) * I have modified the help text to only output with `pihole -v --help` * I have modified all output to be more similar to the output style of `grep` and `curl` (Ditching ":::") Testing output: ``` w3k@MCT:~$ pihole -v Pi-hole version is v3.0.1-14-ga928cd3 (Latest: v3.0.1) Admin Console version is v3.0-9-g3760482 (Latest: v3.0.1) FTL version is v2.6.2 (Latest: v2.6.2) w3k@MCT:~$ pihole -v -c Current Pi-hole version is v3.0.1-14-ga928cd3 Current Admin Console version is v3.0-9-g3760482 Current FTL version is v2.6.2 w3k@MCT:~$ pihole -v -l Latest Pi-hole version is v3.0.1 Latest Admin Console version is v3.0.1 Latest FTL version is v2.6.2 w3k@MCT:~$ pihole -v -p --hash Current Pi-hole hash is a928cd3 w3k@MCT:~$ pihole -v -a --hash Current Admin Console hash is 3760482 w3k@MCT:~$ pihole -v --help Usage: pihole -v [REPO | OPTION] [OPTION] Show Pi-hole, Web Admin & FTL versions w3k@MCT:~$ pihole -v -foo Invalid Option! ``` * Update -h to work as --hash Also provide error output as per https://github.com/pi-hole/pi-hole/pull/1447#issuecomment-300600093 * Perform EXACT searches on HOSTS lists correctly `\s` on the end may be overkill, but it is the existing scanList() behaviour. * Fixed indentation * Minimise string duplication & other minor changes Instead of duplicating output strings, rewrite core/web/ftlOutput() into one neat versionOutput(). * Modified syntax to be valid for Shellcheck * Log and echo gateway responses * Update queryFunc() to search Whitelist If there is a match in Whitelist/Blacklist/Wildcards, `[ ! -t 1 ]` will cause the search to end if the terminal is closed when the script is called. This has the intended effect of allowing a user to search for a W/B/W domain (as well as all the adlists it's found in) using `pihole -q` via Terminal, but the script will stop searching after a W/B/W match when called by the block page. * Wrap in double brackets * Provide remote hashes for version.sh * Provide remote hashes for comparison * Use double braces for all conditions (for consistency) * Suppress potential "cd" error output * Provide "not applicable" output upon any hash request for FTL * whitelist on website blocked doesnt work (#1452) Since Pi-hole redirects ad domains to itself, accessing the script via de.ign.com is the same as pi.hole in this case. The fix should be as simple as adding a / before admin on this line. * Solve piholeLogFlush.sh having to be issued 2 x to clear logs (#1460) Simplified the command -v syntax, and added a sleep 3 timer to the first execution of the log rotation. The second execution was being issued while the first was still running, thus it would fail and you would have to issue the "Flush Logs" command a second time. * Use `echo "ABC" | pihole tricorder` to upload to Pi-hole's medical tricorder. Uses SSL if available. * Update list.sh I believe this has feature parity with `sed /foo/ Id` but also supports busybox, and my alpine docker ;) * Document `sed` substitution for user readability Comment the oneliner with explanations of what each step does. * Update Help Output (#1467) * File consistency * Tabs to 2 spaces * Corrected indenting * Double braced conditionals * Quoted variables within conditionals * Standardise core help text * Added help text for disable command * Added help text for logging command * Clean up * Fixed certain new lines and spaces * Sync with development branch * Formatting consistency * Tabs to 2 spaces * Corrected indenting * Double braced conditionals * Quoted variables within conditionals * Fixed certain newlines and spaces * Admin help text * Added help text for interface command * Sync with development branch * Formatting consistency * Tabs to 2 spaces * Fixed some wording * Fixed certain spaces * Formatting consistency * Minor wording changes * Tabs to 2 spaces * Corrected indenting * Double braced conditionals * Quoted variables within conditionals * Fixed certain newlines and spaces * Blacklist help text * Formatting consistency * Tabs to 2 spaces * Corrected indenting * Cronometer help text * Formatting consistency * Fixed certain newlines and spaces * Corrected indenting * Checkout warning alteration * Add checkout help text * Corrected help output * Show help for "pihole -a -i --help" * Fix "pihole disable --help" and "pihole -l --help" * Show help for "pihole -v -h" * Indent output text * Minor help text change * Show help for "pihole checkout --help" * Tricorder: Insecure Opt-out * Check to see if Tricorder is being called directly * Provide opt-out for insecure transmission of debug log * Remove mention of internal function from help menu * :taco: is the new :shipit: squirrel * Wording changes and bug fix * Fix wildcard help text * -wild is not a valid option since we're already using -wild * Fix logrotation: manual flushing should be done twice, but automated rotation at midnight should only be done *once*! * Print echos only when manual flushing is requested * Add "quiet" mode + update comments in the cron file * Confirm Tricorder is online * Scan port 9998 to confirm the availability of "tricorder.pi-hole.net" * Exit codes for upload process * Formatting consistency * Add link to Windows DNS Swapper See #1400 * Install loopback firewall rules for FTL (#1419) * Install loopback firewall rules for FTL * FirewallD FTL ports Signed-off-by: Dan Schaper * Remove firewallD FTL local rules. Local rules should not be blocked in firewallD, not requred for internal service FTD> * Reinstate https rules, and delete FTL rules Fixes earlier commit. * Retrieve local repos on repair (#1481) * Retrieve local repos on repair * Change conditional to check for repair * Change wording of Update/Reconfigure message * Fixed indenting * Perform "git reset --hard" on reconfigure * Change directory before trying to reset repository. Fixes #1489 * No need to `cd $PWD` as it doesn't affect flow of caller script. Signed-off-by: Dan Schaper * Refine output of password status in basic-install.sh:displayFinalMessage(). Fixes #1488 (#1490) * Rewrite Chronometer to output more stats * Fix output IPv4 addr when removing CIDR notation (#1498) * Move wildcards file if blocking is disabled (#1495) * Move wildcards file if blocking is diabled * Delete newline * Roll back merge #1417 (#1494) * Update ISSUE_TEMPLATE.md * Remove Question option * Prefer ULA over GUA addresses [IPv6] (#1508) * On installs with GUA and ULA's we should prefer ULA's as it's been demonstrated that GUA's can and often are rotated by ISPs. Fixes #1473 * Add test for link-local address detection * Add ULA-only and GUA-only tests * Add test_IPv6_GUA_ULA_test and test_IPv6_ULA_GUA_test * Add "" * Add mock_command_2 command that can mock a command with more than one argument (as "ip -6 address") and result multiple lines of results * Make mock_command_2 more similar to the original mock_command * Correct comments * Fixed remaining comments * Fixed one last comment... * Fixed a comment... * Add weekly logrotation of FTL's log (#1509) * Update LICENSE of the project to EUPL v1.2 * Make clear that NO is the default if the user just hits return (#1514) * Add tricorderFunc back as usable function (#1515) As per #1464 * Don't update FTL when there is a core update (as this will update FTL a second time). Fixes #1516 * Add FTL tests to the test suite (#1510) * Add first version of FTL tests * Wait one second to allow FTL to start up and analyze our mock log * Add test_FTL_telnet_statistics * Added test_FTL_telnet_top_clients * Add test_FTL_telnet_top_domains * Revert "Add FTL tests to the test suite (#1510)" (#1519) This reverts commit cf6a1ac9adb4e26570cc5da7c8be628080f37e0f. * Trim version output when update is successful (#1527) * Change ownership of /etc/pihole to user/group pihole. Fixes #1529 (#1530) * Delete temporary files after installing the FTL binary. Fixes #1525 * Change from admin to approvers teams * Introduce new file black.list for blacklist content * Add "pihole -g -b" to *only* update black.list (saves a bunch of time when adding/changing only blacklisted files - won'tdownload lal lists, but only processes the blacklist and restars dnsmasq) * Remove useless cat * Improve displayed messages and overall logic * Disable black.list on "pihole disable" * cp + rm === mv (well, almost) --- .github/ISSUE_TEMPLATE.md | 2 +- .pullapprove.yml | 4 +- LICENSE | 119 +++---- README.md | 1 + advanced/01-pihole.conf | 1 + advanced/Scripts/chronometer.sh | 479 ++++++++++++++++++++++++----- advanced/Scripts/list.sh | 311 +++++++++---------- advanced/Scripts/piholeCheckout.sh | 32 +- advanced/Scripts/piholeDebug.sh | 8 +- advanced/Scripts/piholeLogFlush.sh | 43 ++- advanced/Scripts/update.sh | 13 +- advanced/Scripts/version.sh | 165 ++++++---- advanced/Scripts/webpage.sh | 187 +++++------ advanced/index.php | 2 +- advanced/logrotate | 11 + advanced/pihole-FTL.service | 2 +- advanced/pihole.cron | 7 +- automated install/basic-install.sh | 98 ++++-- gravity.sh | 109 ++++--- pihole | 207 +++++++++---- test/test_automated_install.py | 76 +++++ 21 files changed, 1227 insertions(+), 650 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 3014625b..23e67795 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -9,7 +9,7 @@ _{replace this text with a number from 1 to 10, with 1 being not familiar, and 10 being very familiar}_ --- -**[FEATURE REQUEST | QUESTION | OTHER]:** +**[BUG REPORT | OTHER]:** Please [submit your feature request here](https://discourse.pi-hole.net/c/feature-requests), so it is votable by the community. It's also easier for us to track. diff --git a/.pullapprove.yml b/.pullapprove.yml index 39566b34..30888234 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -10,7 +10,7 @@ group_defaults: reset_on_push: enabled: true reject_value: -2 - approve_regex: '^(Approved|:shipit:|:\+1:|Engage)' + approve_regex: '^(Approved|:shipit:|:\+1:|Engage|:taco:)' reject_regex: '^(Rejected|:-1:|Borg)' author_approval: auto: true @@ -35,4 +35,4 @@ groups: - master required: 4 teams: - - admin + - approvers diff --git a/LICENSE b/LICENSE index 9fddaad1..9ce6e5b0 100644 --- a/LICENSE +++ b/LICENSE @@ -12,81 +12,63 @@ This license applies to the whole project EXCEPT: The licenses that existed prior to this change have remained intact. ------------------------------------------------------------- +EUROPEAN UNION PUBLIC LICENCE v. 1.2 -European Union Public Licence -V. 1.1 +EUPL © the European Union 2007, 2016 -EUPL (C) the European Community 2007 - -This European Union Public Licence (the "EUPL") applies to the Work or Software (as defined below) which is provided under the terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such use is covered by a right of the copyright holder of the Work). - -The Original Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following notice immediately following the copyright notice for the Original Work: - -Licensed under the EUPL V.1.1 - -or has expressed by any other mean his willingness to license under the EUPL. +This European Union Public Licence (the EUPL) applies to the Work (as defined below) which is provided under the terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such use is covered by a right of the copyright holder of the Work). +The Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following notice immediately following the copyright notice for the Work: +Licensed under the EUPL +or has expressed by any other means his willingness to license under the EUPL. 1. Definitions In this Licence, the following terms have the following meaning: - The Licence: this Licence. - -- The Original Work or the Software: the software distributed and/or communicated by the Licensor under this Licence, available as Source Code and also as Executable Code as the case may be. - +- The Original Work: the work or software distributed or communicated by the Licensor under this Licence, available as Source Code and also as Executable Code as the case may be. - Derivative Works: the works or software that could be created by the Licensee, based upon the Original Work or modifications thereof. This Licence does not define the extent of modification or dependence on the Original Work required in order to classify a work as a Derivative Work; this extent is determined by copyright law applicable in the country mentioned in Article 15. - -- The Work: the Original Work and/or its Derivative Works. - +- The Work: the Original Work or its Derivative Works. - The Source Code: the human-readable form of the Work which is the most convenient for people to study and modify. - - The Executable Code: any code which has generally been compiled and which is meant to be interpreted by a computer as a program. - -- The Licensor: the natural or legal person that distributes and/or communicates the Work under the Licence. - +- The Licensor: the natural or legal person that distributes or communicates the Work under the Licence. - Contributor(s): any natural or legal person who modifies the Work under the Licence, or otherwise contributes to the creation of a Derivative Work. - -- The Licensee or "You": any natural or legal person who makes any usage of the Software under the terms of the Licence. - -- Distribution and/or Communication: any act of selling, giving, lending, renting, distributing, communicating, transmitting, or otherwise making available, on-line or off-line, copies of the Work or providing access to its essential functionalities at the disposal of any other natural or legal person. +- The Licensee or You: any natural or legal person who makes any usage of the Work under the terms of the Licence. +- Distribution or Communication: any act of selling, giving, lending, renting, distributing, communicating, transmitting, or otherwise making available, online or offline, copies of the Work or providing access to its essential functionalities at the disposal of any other natural or legal person. 2. Scope of the rights granted by the Licence -The Licensor hereby grants You a world-wide, royalty-free, non-exclusive, sub-licensable licence to do the following, for the duration of copyright vested in the Original Work: - +The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, sublicensable licence to do the following, for the duration of copyright vested in the Original Work: - use the Work in any circumstance and for all usage, - reproduce the Work, -- modify the Original Work, and make Derivative Works based upon the Work, +- modify the Work, and make Derivative Works based upon the Work, - communicate to the public, including the right to make available or display the Work or copies thereof to the public and perform publicly, as the case may be, the Work, - distribute the Work or copies thereof, - lend and rent the Work or copies thereof, -- sub-license rights in the Work or copies thereof. - +- sublicense rights in the Work or copies thereof. Those rights can be exercised on any media, supports and formats, whether now known or later invented, as far as the applicable law permits so. - In the countries where moral rights apply, the Licensor waives his right to exercise his moral right to the extent allowed by law in order to make effective the licence of the economic rights here above listed. - -The Licensor grants to the Licensee royalty-free, non exclusive usage rights to any patents held by the Licensor, to the extent necessary to make use of the rights granted on the Work under this Licence. +The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to any patents held by the Licensor, to the extent necessary to make use of the rights granted on the Work under this Licence. 3. Communication of the Source Code -The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to distribute and/or communicate the Work. +The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to distribute or communicate the Work. 4. Limitations on copyright -Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the exclusive rights of the rights owners in the Original Work or Software, of the exhaustion of those rights or of other applicable limitations thereto. +Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the exclusive rights of the rights owners in the Work, of the exhaustion of those rights or of other applicable limitations thereto. 5. Obligations of the Licensee The grant of the rights mentioned above is subject to some restrictions and obligations imposed on the Licensee. Those obligations are the following: -Attribution right: the Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the Licence with every copy of the Work he/she distributes and/or communicates. The Licensee must cause any Derivative Work to carry prominent notices stating that the Work has been modified and the date of modification. +Attribution right: The Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the Licence with every copy of the Work he/she distributes or communicates. The Licensee must cause any Derivative Work to carry prominent notices stating that the Work has been modified and the date of modification. -Copyleft clause: If the Licensee distributes and/or communicates copies of the Original Works or Derivative Works based upon the Original Work, this Distribution and/or Communication will be done under the terms of this Licence or of a later version of this Licence unless the Original Work is expressly distributed only under this version of the Licence. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the Work or Derivative Work that alter or restrict the terms of the Licence. +Copyleft clause: If the Licensee distributes or communicates copies of the Original Works or Derivative Works, this Distribution or Communication will be done under the terms of this Licence or of a later version of this Licence unless the Original Work is expressly distributed only under this version of the Licence - for example by communicating EUPL v. 1.2 only. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the Work or Derivative Work that alter or restrict the terms of the Licence. -Compatibility clause: If the Licensee Distributes and/or Communicates Derivative Works or copies thereof based upon both the Original Work and another work licensed under a Compatible Licence, this Distribution and/or Communication can be done under the terms of this Compatible Licence. For the sake of this clause, "Compatible Licence" refers to the licences listed in the appendix attached to this Licence. Should the Licensee’s obligations under the Compatible Licence conflict with his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail. +Compatibility clause: If the Licensee Distributes or Communicates Derivative Works or copies thereof based upon both the Work and another work licensed under a Compatible Licence, this Distribution or Communication can be done under the terms of this Compatible Licence. For the sake of this clause, Compatible Licence refers to the licences listed in the appendix attached to this Licence. Should the Licensee's obligations under the Compatible Licence conflict with his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail. -Provision of Source Code: When distributing and/or communicating copies of the Work, the Licensee will provide a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available for as long as the Licensee continues to distribute and/or communicate the Work. +Provision of Source Code: When distributing or communicating copies of the Work, the Licensee will provide a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available for as long as the Licensee continues to distribute or communicate the Work. Legal Protection: This Licence does not grant permission to use the trade names, trademarks, service marks, or names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the copyright notice. @@ -100,10 +82,8 @@ Each time You accept the Licence, the original Licensor and subsequent Contribut 7. Disclaimer of Warranty -The Work is a work in progress, which is continuously improved by numerous contributors. It is not a finished work and may therefore contain defects or "bugs" inherent to this type of software development. - -For the above reason, the Work is provided under the Licence on an "as is" basis and without warranties of any kind concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this Licence. - +The Work is a work in progress, which is continuously improved by numerous Contributors. It is not a finished work and may therefore contain defects or bugs inherent to this type of development. +For the above reason, the Work is provided under the Licence on an as is basis and without warranties of any kind concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this Licence. This disclaimer of warranty is an essential part of the Licence and a condition for the grant of any rights to the Work. 8. Disclaimer of Liability @@ -112,56 +92,55 @@ Except in the cases of wilful misconduct or damages directly caused to natural p 9. Additional agreements -While distributing the Original Work or Derivative Works, You may choose to conclude an additional agreement to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or services consistent with this Licence. However, in accepting such obligations, You may act only on your own behalf and on your sole responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by the fact You have accepted any such warranty or additional liability. +While distributing the Work, You may choose to conclude an additional agreement, defining obligations or services consistent with this Licence. However, if accepting obligations, You may act only on your own behalf and on your sole responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by the fact You have accepted any warranty or additional liability. 10. Acceptance of the Licence -The provisions of this Licence can be accepted by clicking on an icon "I agree" placed under the bottom of a window displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms and conditions. - -Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution and/or Communication by You of the Work or copies thereof. +The provisions of this Licence can be accepted by clicking on an icon I agree placed under the bottom of a window displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms and conditions. +Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution or Communication by You of the Work or copies thereof. 11. Information to the public -In case of any Distribution and/or Communication of the Work by means of electronic communication by You (for example, by offering to download the Work from a remote location) the distribution channel or media (for example, a website) must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence and the way it may be accessible, concluded, stored and reproduced by the Licensee. +In case of any Distribution or Communication of the Work by means of electronic communication by You (for example, by offering to download the Work from a remote location) the distribution channel or media (for example, a website) must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence and the way it may be accessible, concluded, stored and reproduced by the Licensee. 12. Termination of the Licence The Licence and the rights granted hereunder will terminate automatically upon any breach by the Licensee of the terms of the Licence. - Such a termination will not terminate the licences of any person who has received the Work from the Licensee under the Licence, provided such persons remain in full compliance with the Licence. 13. Miscellaneous -Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the Work licensed hereunder. - -If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or enforceability of the Licence as a whole. Such provision will be construed and/or reformed so as necessary to make it valid and enforceable. - -The European Commission may publish other linguistic versions and/or new versions of this Licence, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence. New versions of the Licence will be published with a unique version number. - +Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the Work. +If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or enforceability of the Licence as a whole. Such provision will be construed or reformed so as necessary to make it valid and enforceable. +The European Commission may publish other linguistic versions or new versions of this Licence or updated versions of the Appendix, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence. New versions of the Licence will be published with a unique version number. All linguistic versions of this Licence, approved by the European Commission, have identical value. Parties can take advantage of the linguistic version of their choice. 14. Jurisdiction -Any litigation resulting from the interpretation of this License, arising between the European Commission, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice of the European Communities, as laid down in article 238 of the Treaty establishing the European Community. - -Any litigation arising between Parties, other than the European Commission, and resulting from the interpretation of this License, will be subject to the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business. +Without prejudice to specific agreement between parties, +- any litigation resulting from the interpretation of this License, arising between the European Union institutions, bodies, offices or agencies, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice of the European Union, as laid down in article 272 of the Treaty on the Functioning of the European Union, +- any litigation arising between other parties and resulting from the interpretation of this License, will be subject to the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business. 15. Applicable Law -This Licence shall be governed by the law of the European Union country where the Licensor resides or has his registered office. - -This licence shall be governed by the Belgian law if: - -- a litigation arises between the European Commission, as a Licensor, and any Licensee; -- the Licensor, other than the European Commission, has no residence or registered office inside a European Union country. - +Without prejudice to specific agreement between parties, +- this Licence shall be governed by the law of the European Union Member State where the Licensor has his seat, resides or has his registered office, +- this licence shall be governed by Belgian law if the Licensor has no seat, residence or registered office inside a European Union Member State. === + Appendix -"Compatible Licences" according to article 5 EUPL are: -- GNU General Public License (GNU GPL) v. 2 +Compatible Licences according to Article 5 EUPL are: +- GNU General Public License (GPL) v. 2, v. 3 +- GNU Affero General Public License (AGPL) v. 3 - Open Software License (OSL) v. 2.1, v. 3.0 -- Common Public License v. 1.0 -- Eclipse Public License v. 1.0 -- Cecill v. 2.0 +- Eclipse Public License (EPL) v. 1.0 +- CeCILL v. 2.0, v. 2.1 +- Mozilla Public Licence (MPL) v. 2 +- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 +- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for works other than software +- European Union Public Licence (EUPL) v. 1.1, v. 1.2 +- Québec Free and Open-Source Licence - Reciprocity (LiLiQ-R) or Strong Reciprocity (LiLiQ-R+) +- The European Commission may update this Appendix to later versions of the above licences without producing a new version of the EUPL, as long as they provide the rights granted in Article 2 of this Licence and protect the covered Source Code from exclusive appropriation. +- All other changes or additions to this Appendix require the production of a new EUPL version. diff --git a/README.md b/README.md index 75c548e5..6f8813fa 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,7 @@ You can view [real-time stats](https://discourse.pi-hole.net/t/how-do-i-view-my- - [Let your blink1 device blink when Pi-hole filters ads](https://gist.github.com/elpatron68/ec0b4c582e5abf604885ac1e068d233f) - [Pi-hole Prometheus exporter](https://github.com/nlamirault/pihole_exporter): a [Prometheus](https://prometheus.io/) exporter for Pi-hole - [Pi-hole Droid - open source Android client](https://github.com/friimaind/pi-hole-droid) +- [Windows DNS Swapper](https://github.com/roots84/DNS-Swapper), see [#1400](https://github.com/pi-hole/pi-hole/issues/1400) ## Coverage diff --git a/advanced/01-pihole.conf b/advanced/01-pihole.conf index 1b157f88..79735c15 100644 --- a/advanced/01-pihole.conf +++ b/advanced/01-pihole.conf @@ -22,6 +22,7 @@ addn-hosts=/etc/pihole/gravity.list addn-hosts=/etc/pihole/local.list +addn-hosts=/etc/pihole/black.list domain-needed diff --git a/advanced/Scripts/chronometer.sh b/advanced/Scripts/chronometer.sh index 67ff495b..d9b7d05b 100755 --- a/advanced/Scripts/chronometer.sh +++ b/advanced/Scripts/chronometer.sh @@ -8,101 +8,428 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. -#Functions############################################################################################################## -piLog="/var/log/pihole.log" -gravity="/etc/pihole/gravity.list" - -. /etc/pihole/setupVars.conf - -function GetFTLData { +# Retrieve stats from FTL engine +pihole-FTL() { + ftl_port=$(cat /var/run/pihole-FTL.port 2> /dev/null) + if [[ -n "$ftl_port" ]]; then # Open connection to FTL - exec 3<>/dev/tcp/localhost/"$(cat /var/run/pihole-FTL.port)" + exec 3<>"/dev/tcp/localhost/$ftl_port" # Test if connection is open - if { >&3; } 2> /dev/null; then - # Send command to FTL - echo -e ">$1" >&3 + if { "true" >&3; } 2> /dev/null; then + # Send command to FTL + echo -e ">$1" >&3 - # Read input - read -r -t 1 LINE <&3 - until [ ! $? ] || [[ "$LINE" == *"EOM"* ]]; do - echo "$LINE" >&1 - read -r -t 1 LINE <&3 - done + # Read input + read -r -t 1 LINE <&3 + until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do + echo "$LINE" >&1 + read -r -t 1 LINE <&3 + done - # Close connection - exec 3>&- - exec 3<&- + # Close connection + exec 3>&- + exec 3<&- fi + else + echo -e "${COL_LIGHT_RED}FTL offline${COL_NC}" + fi } -outputJSON() { - get_summary_data - echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}" +# Print spaces to align right-side content +printFunc() { + txt_len="${#2}" + + # Reduce string length when using colour code + [ "${2:0:1}" == "" ] && txt_len=$((txt_len-7)) + + if [[ "$3" == "last" ]]; then + # Prevent final line from printing trailing newline + scr_size=( $(stty size 2>/dev/null || echo 24 80) ) + scr_width="${scr_size[1]}" + + title_len="${#1}" + spc_num=$(( (scr_width - title_len) - txt_len )) + [[ "$spc_num" -lt 0 ]] && spc_num="0" + spc=$(printf "%${spc_num}s") + + printf "%s%s$spc" "$1" "$2" + else + # Determine number of spaces for padding + spc_num=$(( 20 - txt_len )) + [[ "$spc_num" -lt 0 ]] && spc_num="0" + spc=$(printf "%${spc_num}s") + + # Print string (Max 20 characters, prevents overflow) + printf "%s%s$spc" "$1" "${2:0:20}" + fi } -get_summary_data() { - local summary=$(GetFTLData "stats") - domains_being_blocked_raw=$(grep "domains_being_blocked" <<< "${summary}" | grep -Eo "[0-9]+$") - domains_being_blocked=$(printf "%'.f" ${domains_being_blocked_raw}) - dns_queries_today_raw=$(grep "dns_queries_today" <<< "$summary" | grep -Eo "[0-9]+$") - dns_queries_today=$(printf "%'.f" ${dns_queries_today_raw}) - ads_blocked_today_raw=$(grep "ads_blocked_today" <<< "$summary" | grep -Eo "[0-9]+$") - ads_blocked_today=$(printf "%'.f" ${ads_blocked_today_raw}) - ads_percentage_today_raw=$(grep "ads_percentage_today" <<< "$summary" | grep -Eo "[0-9.]+$") - LC_NUMERIC=C ads_percentage_today=$(printf "%'.f" ${ads_percentage_today_raw}) +# Perform on first Chrono run (not for JSON formatted string) +get_init_stats() { + LC_NUMERIC=C + calcFunc(){ awk "BEGIN {print $*}"; } + + # Convert bytes to human-readable format + hrBytes() { + awk '{ + num=$1; + if(num==0) { + print "0 B" + } else { + xxx=(num<0?-num:num) + sss=(num<0?-1:1) + split("B KB MB GB TB PB",type) + for(i=5;yyy < 1;i--) { + yyy=xxx / (2^(10*i)) + } + printf "%.0f " type[i+2], yyy*sss + } + }' <<< "$1"; + } + + # Convert seconds to human-readable format + hrSecs() { + day=$(( $1/60/60/24 )); hrs=$(( $1/3600%24 )); mins=$(( ($1%3600)/60 )); secs=$(( $1%60 )) + [[ "$day" -ge "2" ]] && plu="s" + [[ "$day" -ge "1" ]] && days="$day day${plu}, " || days="" + printf "%s%02d:%02d:%02d\n" "$days" "$hrs" "$mins" "$secs" + } + + # Set Colour Codes + coltable="/opt/pihole/COL_TABLE" + if [[ -f "${coltable}" ]]; then + source ${coltable} + else + COL_NC='' + COL_DARK_GRAY='' + COL_LIGHT_GREEN='' + COL_LIGHT_BLUE='' + COL_LIGHT_RED='' + COL_YELLOW='' + COL_LIGHT_RED='' + COL_URG_RED='' + fi + + # Get RPi model number, or OS distro info + if command -v vcgencmd &> /dev/null; then + sys_rev=$(awk '/Revision/ {print $3}' < /proc/cpuinfo) + case "$sys_rev" in + 000[2-6]) sys_model=" 1, Model B";; # 256MB + 000[7-9]) sys_model=" 1, Model A" ;; # 256MB + 000d|000e|000f) sys_model=" 1, Model B";; # 512MB + 0010|0013) sys_model=" 1, Model B+";; # 512MB + 0012|0015) sys_model=" 1, Model A+";; # 256MB + a0104[0-1]|a21041|a22042) sys_model=" 2, Model B";; # 1GB + 900021) sys_model=" 1, Model A+";; # 512MB + 900032) sys_model=" 1, Model B+";; # 512MB + 90009[2-3]|920093) sys_model=" Zero";; # 512MB + 9000c1) sys_model=" Zero W";; # 512MB + a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB + *) sys_model="" ;; + esac + sys_type="Raspberry Pi$sys_model" + else + source "/etc/os-release" + CODENAME=$(sed 's/[()]//g' <<< "${VERSION/* /}") + sys_type="${NAME/ */} ${CODENAME^} $VERSION_ID" + fi + + # Get core count + sys_cores=$(grep -c "^processor" /proc/cpuinfo) + [[ "$sys_cores" -ne 1 ]] && sys_cores_plu="cores" || sys_cores_plu="core" + + # Test existence of clock speed file for ARM CPU + if [[ -f "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]]; then + scaling_freq_file="/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" + fi + + # Test existence of temperature file + if [[ -f "/sys/class/thermal/thermal_zone0/temp" ]]; then + temp_file="/sys/class/thermal/thermal_zone0/temp" + elif [[ -f "/sys/class/hwmon/hwmon0/temp1_input" ]]; then + temp_file="/sys/class/hwmon/hwmon0/temp1_input" + else + temp_file="" + fi + + # Test existence of setupVars config + if [[ -f "/etc/pihole/setupVars.conf" ]]; then + setupVars="/etc/pihole/setupVars.conf" + fi } -normalChrono() { - for (( ; ; )); do - get_summary_data - domain=$(GetFTLData recentBlocked) - clear - # Displays a colorful Pi-hole logo - echo " ___ _ _ _" - echo "| _ (_)___| |_ ___| |___" - echo "| _/ |___| ' \/ _ \ / -_)" - echo "|_| |_| |_||_\___/_\___|" - echo "" - echo " ${IPV4_ADDRESS}" - echo "" - uptime | cut -d' ' -f11- - #uptime -p #Doesn't work on all versions of uptime - uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}' - echo "-------------------------------" - echo "Recently blocked:" - echo " $domain" +get_sys_stats() { + local ph_ver_raw + local cpu_raw + local ram_raw + local disk_raw - echo "Blocking: ${domains_being_blocked}" - echo "Queries: ${dns_queries_today}" - echo "Pi-holed: ${ads_blocked_today} (${ads_percentage_today}%)" - - sleep 5 - done + # Update every 12 refreshes (Def: every 60s) + count=$((count+1)) + if [[ "$count" == "1" ]] || (( "$count" % 12 == 0 )); then + [[ -n "$setupVars" ]] && source "$setupVars" + + + ph_ver_raw=($(pihole -v -c 2> /dev/null | sed -n 's/^.* v/v/p')) + if [[ -n "${ph_ver_raw[0]}" ]]; then + ph_core_ver="${ph_ver_raw[0]}" + ph_lte_ver="${ph_ver_raw[1]}" + ph_ftl_ver="${ph_ver_raw[2]}" + else + ph_core_ver="${COL_LIGHT_RED}API unavailable${COL_NC}" + fi + + sys_name=$(hostname) + + [[ -n "$TEMPERATUREUNIT" ]] && temp_unit="$TEMPERATUREUNIT" || temp_unit="c" + + # Get storage stats for partition mounted on / + disk_raw=($(df -B1 / 2> /dev/null | awk 'END{ print $3,$2,$5 }')) + disk_used="${disk_raw[0]}" + disk_total="${disk_raw[1]}" + disk_perc="${disk_raw[2]}" + + net_gateway=$(route -n | awk '$4 == "UG" {print $2;exit}') + + # Get DHCP stats, if feature is enabled + if [[ "$DHCP_ACTIVE" == "true" ]]; then + ph_dhcp_eip="${DHCP_END##*.}" + ph_dhcp_max=$(( ${DHCP_END##*.} - ${DHCP_START##*.} + 1 )) + fi + + # Get alt DNS server, or print total count of alt DNS servers + if [[ -z "${PIHOLE_DNS_3}" ]]; then + ph_alts="${PIHOLE_DNS_2}" + else + dns_count="0" + [[ -n "${PIHOLE_DNS_2}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_3}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_4}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_5}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_6}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_7}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_8}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_9}" ]] && dns_count="$dns_count+" + ph_alts="${dns_count} others" + fi + fi + + sys_uptime=$(hrSecs "$(cut -d. -f1 /proc/uptime)") + sys_loadavg=$(cut -d " " -f1,2,3 /proc/loadavg) + + # Get CPU usage, only counting processes over 1% CPU as active + cpu_raw=$(ps -eo pcpu,rss --no-headers | grep -E -v " 0") + cpu_tasks=$(wc -l <<< "$cpu_raw") + cpu_taskact=$(sed -r "/(^ 0.)/d" <<< "$cpu_raw" | wc -l) + cpu_perc=$(awk '{sum+=$1} END {printf "%.0f\n", sum/'"$sys_cores"'}' <<< "$cpu_raw") + + # Get CPU clock speed + if [[ -n "$scaling_freq_file" ]]; then + cpu_mhz=$(( $(< /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 )) + else + cpu_mhz=$(lscpu | awk -F "[ .]+" '/MHz/ {print $4;exit}') + fi + + # Determine correct string format for CPU clock speed + if [[ -n "$cpu_mhz" ]]; then + [[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(calcFunc "$cpu_mhz"/1000) Ghz" + [[ -n "$cpu_freq" ]] && cpu_freq_str=" @ $cpu_freq" || cpu_freq_str="" + fi + + # Determine colour for temperature + if [[ -n "$temp_file" ]]; then + if [[ "$temp_unit" == "C" ]]; then + cpu_temp=$(printf "%'.0fc\n" "$(calcFunc "$(< $temp_file) / 1000")") + + case "${cpu_temp::-1}" in + -*|[0-9]|[1-3][0-9]) cpu_col="$COL_LIGHT_BLUE";; + 4[0-9]) cpu_col="";; + 5[0-9]) cpu_col="$COL_YELLOW";; + 6[0-9]) cpu_col="$COL_LIGHT_RED";; + *) cpu_col="$COL_URG_RED";; + esac + + # $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED + cpu_temp_str=", $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY" + + elif [[ "$temp_unit" == "F" ]]; then + cpu_temp=$(printf "%'.0ff\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")") + + case "${cpu_temp::-1}" in + -*|[0-9]|[0-9][0-9]) cpu_col="$COL_LIGHT_BLUE";; + 1[0-1][0-9]) cpu_col="";; + 1[2-3][0-9]) cpu_col="$COL_YELLOW";; + 1[4-5][0-9]) cpu_col="$COL_LIGHT_RED";; + *) cpu_col="$COL_URG_RED";; + esac + + cpu_temp_str=", $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY" + + else + cpu_temp_str=$(printf ", %'.0fk\n" "$(calcFunc "($(< $temp_file) / 1000) + 273.15")") + fi + else + cpu_temp_str="" + fi + + ram_raw=($(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.0f %.0f %.0f", (total-free-buffers-cached)*100/total, (total-free-buffers-cached)*1024, total*1024}' /proc/meminfo)) + ram_perc="${ram_raw[0]}" + ram_used="${ram_raw[1]}" + ram_total="${ram_raw[2]}" + + if [[ "$(pihole status web 2> /dev/null)" == "1" ]]; then + ph_status="${COL_LIGHT_GREEN}Active" + else + ph_status="${COL_LIGHT_RED}Inactive" + fi + + if [[ "$DHCP_ACTIVE" == "true" ]]; then + ph_dhcp_num=$(wc -l 2> /dev/null < "/etc/pihole/dhcp.leases") + fi } -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 0 +get_ftl_stats() { + local stats_raw + + stats_raw=($(pihole-FTL "stats")) + domains_being_blocked_raw="${stats_raw[1]}" + dns_queries_today_raw="${stats_raw[3]}" + ads_blocked_today_raw="${stats_raw[5]}" + ads_percentage_today_raw="${stats_raw[7]}" + + # Only retrieve these stats when not called from jsonFunc + if [[ -z "$1" ]]; then + local recent_blocked_raw + local top_ad_raw + local top_domain_raw + local top_client_raw + + domains_being_blocked=$(printf "%'.0f\n" "${domains_being_blocked_raw}") + dns_queries_today=$(printf "%'.0f\n" "${dns_queries_today_raw}") + ads_blocked_today=$(printf "%'.0f\n" "${ads_blocked_today_raw}") + ads_percentage_today=$(printf "%'.0f\n" "${ads_percentage_today_raw}") + + recent_blocked_raw=$(pihole-FTL recentBlocked) + top_ad_raw=($(pihole-FTL "top-ads (1)")) + top_domain_raw=($(pihole-FTL "top-domains (1)")) + top_client_raw=($(pihole-FTL "top-clients (1)")) + + # Limit strings to 40 characters to prevent overflow + recent_blocked="${recent_blocked_raw:0:40}" + top_ad="${top_ad_raw[2]:0:40}" + top_domain="${top_domain_raw[2]:0:40}" + [[ "${top_client_raw[3]}" ]] && top_client="${top_client_raw[3]:0:40}" || top_client="${top_client_raw[2]:0:40}" + fi +} + +chronoFunc() { + get_init_stats + + for (( ; ; )); do + get_sys_stats + get_ftl_stats + + # Do not print LTE/FTL strings if API is unavailable + ph_core_str=" ${COL_DARK_GRAY}Pi-hole: $ph_core_ver${COL_NC}" + if [[ -n "$ph_lte_ver" ]]; then + ph_lte_str=" ${COL_DARK_GRAY}AdminLTE: $ph_lte_ver${COL_NC}" + ph_ftl_str=" ${COL_DARK_GRAY}FTL: $ph_ftl_ver${COL_NC}" + fi + + clear + + echo -e "|¯¯¯(¯)__|¯|_ ___|¯|___$ph_core_str +| ¯_/¯|__| ' \/ _ \ / -_)$ph_lte_str +|_| |_| |_||_\___/_\___|$ph_ftl_str + ${COL_DARK_GRAY}——————————————————————————————————————————————————————————${COL_NC}" + + printFunc " Hostname: " "$sys_name" + [ -n "$sys_type" ] && printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$sys_type" "$COL_NC" || printf "\n" + + printf "%s\n" " Uptime: $sys_uptime" + + printFunc " Task Load: " "$sys_loadavg" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Active: $cpu_taskact of $cpu_tasks tasks" "$COL_NC" + + printFunc " CPU usage: " "$cpu_perc%" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$sys_cores $sys_cores_plu$cpu_freq_str$cpu_temp_str" "$COL_NC" + + printFunc " RAM usage: " "$ram_perc%" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Used: $(hrBytes "$ram_used") of $(hrBytes "$ram_total")" "$COL_NC" + + printFunc " HDD usage: " "$disk_perc" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Used: $(hrBytes "$disk_used") of $(hrBytes "$disk_total")" "$COL_NC" + + printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Gateway: $net_gateway" "$COL_NC" + + if [[ "$DHCP_ACTIVE" == "true" ]]; then + printFunc " DHCP: " "$DHCP_START to $ph_dhcp_eip" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Leased: $ph_dhcp_num of $ph_dhcp_max" "$COL_NC" + fi + + printFunc " Pi-hole: " "$ph_status" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Blocking: $domains_being_blocked sites" "$COL_NC" + + printFunc " Ads Today: " "$ads_percentage_today%" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$ads_blocked_today of $dns_queries_today queries" "$COL_NC" + + printFunc " Fwd DNS: " "$PIHOLE_DNS_1" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Alt DNS: $ph_alts" "$COL_NC" + + echo -e " ${COL_DARK_GRAY}——————————————————————————————————————————————————————————${COL_NC}" + echo " Recently blocked: $recent_blocked" + echo " Top Advertiser: $top_ad" + echo " Top Domain: $top_domain" + printFunc " Top Client: " "$top_client" "last" + + if [[ "$1" == "exit" ]]; then + exit 0 + else + if [[ -n "$1" ]]; then + sleep "${1}" + else + sleep 5 + fi + fi + + done +} + +jsonFunc() { + get_ftl_stats "json" + echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}" +} + +helpFunc() { + if [[ "$1" == "?" ]]; then + echo "Unknown option. Please view 'pihole -c --help' for more information" + else + echo "Usage: pihole -c [options] +Example: 'pihole -c -j' +Calculates stats and displays to an LCD + +Options: + -j, --json Output stats as JSON formatted string + -r, --refresh Set update frequency (in seconds) + -e, --exit Output stats and exit witout refreshing + -h, --help Display this help text" + fi + + exit 0 } if [[ $# = 0 ]]; then - normalChrono + chronoFunc fi for var in "$@"; do - case "$var" in - "-j" | "--json" ) outputJSON;; - "-h" | "--help" ) displayHelp;; - * ) exit 1;; - esac + case "$var" in + "-j" | "--json" ) jsonFunc;; + "-h" | "--help" ) helpFunc;; + "-r" | "--refresh" ) chronoFunc "$2";; + "-e" | "--exit" ) chronoFunc "exit";; + * ) helpFunc "?";; + esac done diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh index 537ebac3..308e1f5e 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -3,14 +3,12 @@ # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. # -# Whitelists and blacklists domains +# Whitelist and blacklist domains # # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. - - -#globals +# Globals basename=pihole piholeDir=/etc/${basename} whitelist=${piholeDir}/whitelist.txt @@ -27,122 +25,118 @@ listMain="" listAlt="" helpFunc() { + if [[ "${listMain}" == "${whitelist}" ]]; then + param="w" + type="white" + elif [[ "${listMain}" == "${wildcardlist}" ]]; then + param="wild" + type="wildcard black" + else + param="b" + type="black" + fi - if [[ ${listMain} == ${whitelist} ]]; then - letter="w" - word="white" - else - letter="b" - word="black" - fi + echo "Usage: pihole -${param} [options] +Example: 'pihole -${param} site.com', or 'pihole -${param} site1.com site2.com' +${type^}list one or more domains - 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 -if [[ "${letter}" == "b" ]]; then - echo "::: -wild, --wildcard Add wildcard entry (only blacklist)" -fi - exit 0 +Options: + -d, --delmode Remove domain(s) from the ${type}list + -nr, --noreload Update ${type}list without refreshing dnsmasq + -q, --quiet Make output less verbose + -h, --help Show this help dialog + -l, --list Display all your ${type}listed domains" + + exit 0 } EscapeRegexp() { - # This way we may safely insert an arbitrary - # string in our regular expressions - # Also remove leading "." if present - echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g" + # This way we may safely insert an arbitrary + # string in our regular expressions + # Also remove leading "." if present + echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g" } -HandleOther(){ - # First, convert everything to lowercase - domain=$(sed -e "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" <<< "$1") +HandleOther() { + # First, convert everything to lowercase + domain=$(sed -e "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" <<< "$1") - #check validity of domain - validDomain=$(echo "${domain}" | perl -lne 'print if /(?!.*[^a-z0-9-\.].*)^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9-]+\.)*[a-z]{2,63}/') - if [ -z "${validDomain}" ]; then - echo "::: $1 is not a valid argument or domain name" - else - domList=("${domList[@]}" ${validDomain}) - fi + # Check validity of domain + validDomain=$(echo "${domain}" | perl -lne 'print if /(?!.*[^a-z0-9-\.].*)^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9-]+\.)*[a-z]{2,63}/') + 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}" - if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then - RemoveDomain "${dom}" "${wildcardlist}" - fi - else - RemoveDomain "${dom}" "${listMain}" - fi - done + # Check whitelist file exists, and if not, create it + if [[ ! -f ${whitelist} ]]; then + touch ${whitelist} + fi + + for dom in "${domList[@]}"; do + # Logic: If addmode then add to desired list and remove from the other; if delmode then remove from desired list but do not add to the other + if ${addmode}; then + AddDomain "${dom}" "${listMain}" + RemoveDomain "${dom}" "${listAlt}" + if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then + RemoveDomain "${dom}" "${wildcardlist}" + fi + else + RemoveDomain "${dom}" "${listMain}" + fi + done } AddDomain() { - list="$2" - domain=$(EscapeRegexp "$1") + list="$2" + domain=$(EscapeRegexp "$1") - if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then + if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then + bool=true + # Is the domain in the list we want to add it to? + grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false - bool=true - #Is the domain in the list we want to add it to? - grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false + if [[ "${bool}" == false ]]; then + # Domain not found in the whitelist file, add it! + if [[ "${verbose}" == true ]]; then + echo "::: 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 + elif [[ "${list}" == "${wildcardlist}" ]]; then + source "${piholeDir}/setupVars.conf" + # Remove the /* from the end of the IPv4addr. + IPV4_ADDRESS=${IPV4_ADDRESS%/*} + IPV6_ADDRESS=${IPV6_ADDRESS} - 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 + bool=true + # Is the domain in the list? + grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false - elif [[ "${list}" == "${wildcardlist}" ]]; then - - source "${piholeDir}/setupVars.conf" - #Remove the /* from the end of the IPv4addr. - IPV4_ADDRESS=${IPV4_ADDRESS%/*} - IPV6_ADDRESS=${IPV6_ADDRESS} - - bool=true - #Is the domain in the list? - grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false - - if [[ "${bool}" == false ]]; then - if [[ "${verbose}" == true ]]; then - echo "::: Adding $1 to wildcard blacklist..." - fi - reload=true - echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}" - if [[ ${#IPV6_ADDRESS} > 0 ]] ; then - echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}" - fi - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} already exists in wildcard blacklist, no need to add!" - fi - fi - fi + if [[ "${bool}" == false ]]; then + if [[ "${verbose}" == true ]]; then + echo "::: Adding $1 to wildcard blacklist..." + fi + reload=true + echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}" + if [[ "${#IPV6_ADDRESS}" > 0 ]]; then + echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}" + fi + else + if [[ "${verbose}" == true ]]; then + echo "::: ${1} already exists in wildcard blacklist, no need to add!" + fi + fi + fi } RemoveDomain() { @@ -150,85 +144,82 @@ RemoveDomain() { domain=$(EscapeRegexp "$1") if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then - - bool=true - #Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa - grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false - if [[ "${bool}" == true ]]; then - # Remove it from the other one - echo "::: Removing $1 from $list..." - # /I flag: search case-insensitive - sed -i "/${domain}/Id" "${list}" - reload=true - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} does not exist in ${list}, no need to remove!" - fi + bool=true + # Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa + grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false + if [[ "${bool}" == true ]]; then + # Remove it from the other one + echo "::: Removing $1 from $list..." + # /I flag: search case-insensitive + sed -i "/${domain}/Id" "${list}" + reload=true + else + if [[ "${verbose}" == true ]]; then + echo "::: ${1} does not exist in ${list}, no need to remove!" fi - + fi elif [[ "${list}" == "${wildcardlist}" ]]; then - - bool=true - #Is it in the list? - grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false - if [[ "${bool}" == true ]]; then - # Remove it from the other one - echo "::: Removing $1 from $list..." - # /I flag: search case-insensitive - sed -i "/address=\/${domain}/Id" "${list}" - reload=true - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} does not exist in ${list}, no need to remove!" - fi + bool=true + # Is it in the list? + grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false + if [[ "${bool}" == true ]]; then + # Remove it from the other one + echo "::: Removing $1 from $list..." + # /I flag: search case-insensitive + sed -i "/address=\/${domain}/Id" "${list}" + reload=true + else + if [[ "${verbose}" == true ]]; then + echo "::: ${1} does not exist in ${list}, no need to remove!" fi + fi fi } Reload() { - # Reload hosts file - pihole -g -sd + # 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; + 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}";; - "-wild" | "wildcard" ) listMain="${wildcardlist}";; - "-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 + case "${var}" in + "-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";; + "-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";; + "-wild" | "wildcard" ) listMain="${wildcardlist}";; + "-nr"| "--noreload" ) reload=false;; + "-d" | "--delmode" ) addmode=false;; + "-f" | "--force" ) force=true;; + "-q" | "--quiet" ) verbose=false;; + "-h" | "--help" ) helpFunc;; + "-l" | "--list" ) Displaylist;; + * ) HandleOther "${var}";; + esac done shift if [[ $# = 0 ]]; then - helpFunc + helpFunc fi PoplistFile if ${reload}; then - Reload + Reload fi diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh index 09f20d6b..e2c0ab11 100644 --- a/advanced/Scripts/piholeCheckout.sh +++ b/advanced/Scripts/piholeCheckout.sh @@ -3,7 +3,7 @@ # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. # -# Checkout other branches than master +# Switch Pi-hole subsystems to a different Github branch # # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. @@ -18,9 +18,12 @@ PH_TEST="true" source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" # setupVars set in basic-install.sh source "${setupVars}" - update="false" +# Colour codes +red="\e[1;31m" +def="\e[0m" + fully_fetch_repo() { # Add upstream branches to shallow clone local directory="${1}" @@ -35,7 +38,7 @@ fully_fetch_repo() { return 0 } -get_available_branches(){ +get_available_branches() { # Return available branches local directory="${1}" @@ -54,6 +57,8 @@ fetch_checkout_pull_branch() { # Set the reference for the requested branch, fetch, check it put and pull it cd "${directory}" git remote set-branches origin "${branch}" || return 1 + git stash --all --quiet &> /dev/null || true + git clean --force -d || true git fetch --quiet || return 1 checkout_pull_branch "${directory}" "${branch}" || return 1 } @@ -79,23 +84,23 @@ checkout_pull_branch() { } warning1() { - echo "::: Note that changing the branch is a severe change of your Pi-hole system." - echo "::: This is not supported unless one of the developers explicitly asks you to do this!" - read -r -p "::: Have you read and understood this? [y/N] " response + echo " Please note that changing branches severely alters your Pi-hole subsystems" + echo " Features that work on the master branch, may not on a development branch" + echo -e " ${red}This feature is NOT supported unless a Pi-hole developer explicitly asks!${def}" + read -r -p " Have you read and understood this? [y/N] " response case ${response} in [yY][eE][sS]|[yY]) - echo "::: Continuing." + echo "::: Continuing with branch change." return 0 ;; *) - echo "::: Aborting." + echo "::: Branch change has been cancelled." return 1 ;; esac } -checkout() -{ +checkout() { local corebranches local webbranches @@ -192,11 +197,10 @@ checkout() if [[ ! "${1}" == "web" && "${update}" == "true" ]]; then echo "::: Running installer to upgrade your installation" if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then - exit 0 + exit 0 else - echo "Unable to complete update, contact Pi-hole" - exit 1 + echo "Unable to complete update, contact Pi-hole" + exit 1 fi fi } - diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 10dd1e8b..8020cc80 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -260,18 +260,18 @@ ip_ping_check() { if [[ -n ${ip_def_gateway} ]]; then echo -n "::: Pinging default IPv${protocol} gateway: " if ! ping_gateway="$(${cmd} -q -W 3 -c 3 -n ${ip_def_gateway} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then - echo "Gateway did not respond." + log_echo "Gateway did not respond." return 1 else - echo "Gateway responded." + log_echo "Gateway responded." log_write "${ping_gateway}" fi echo -n "::: Pinging Internet via IPv${protocol}: " if ! ping_inet="$(${cmd} -q -W 3 -c 3 -n ${g_addr} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then - echo "Query did not respond." + log_echo "Query did not respond." return 1 else - echo "Query responded." + log_echo "Query responded." log_write "${ping_inet}" fi else diff --git a/advanced/Scripts/piholeLogFlush.sh b/advanced/Scripts/piholeLogFlush.sh index fd66b255..cc553b32 100755 --- a/advanced/Scripts/piholeLogFlush.sh +++ b/advanced/Scripts/piholeLogFlush.sh @@ -8,17 +8,38 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. -echo -n "::: Flushing /var/log/pihole.log ..." -# Test if logrotate is available on this system -if command -v /usr/sbin/logrotate &> /dev/null; then - # Flush twice to move all data out of sight of FTL - /usr/sbin/logrotate --force /etc/pihole/logrotate - /usr/sbin/logrotate --force /etc/pihole/logrotate +if [[ "$@" != *"quiet"* ]]; then + echo -n "::: Flushing /var/log/pihole.log ..." +fi +if [[ "$@" == *"once"* ]]; then + # Nightly logrotation + if command -v /usr/sbin/logrotate >/dev/null; then + # Logrotate once + /usr/sbin/logrotate --force /etc/pihole/logrotate + else + # Copy pihole.log over to pihole.log.1 + # and empty out pihole.log + # Note that moving the file is not an option, as + # dnsmasq would happily continue writing into the + # moved file (it will have the same file handler) + cp /var/log/pihole.log /var/log/pihole.log.1 + echo " " > /var/log/pihole.log + fi else - # Flush both pihole.log and pihole.log.1 (if existing) - echo " " > /var/log/pihole.log - if [ -f /var/log/pihole.log.1 ]; then - echo " " > /var/log/pihole.log.1 + # Manual flushing + if command -v /usr/sbin/logrotate >/dev/null; then + # Logrotate twice to move all data out of sight of FTL + /usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3 + /usr/sbin/logrotate --force /etc/pihole/logrotate + else + # Flush both pihole.log and pihole.log.1 (if existing) + echo " " > /var/log/pihole.log + if [ -f /var/log/pihole.log.1 ]; then + echo " " > /var/log/pihole.log.1 + fi fi fi -echo "... done!" + +if [[ "$@" != *"quiet"* ]]; then + echo "... done!" +fi diff --git a/advanced/Scripts/update.sh b/advanced/Scripts/update.sh index 4fceb931..6aef183b 100755 --- a/advanced/Scripts/update.sh +++ b/advanced/Scripts/update.sh @@ -117,7 +117,10 @@ main() { echo "::: FTL: up to date" fi - if ${FTL_update}; then + # Logic: Don't update FTL when there is a core update available + # since the core update will run the installer which will itself + # re-install (i.e. update) FTL + if ${FTL_update} && ! ${core_update}; then echo ":::" echo "::: FTL out of date" FTLdetect @@ -194,21 +197,21 @@ main() { if [[ "${web_update}" == true ]]; then web_version_current="$(/usr/local/bin/pihole version --admin --current)" echo ":::" - echo "::: Web Admin version is now at ${web_version_current}" + echo "::: Web Admin version is now at ${web_version_current/* v/v}}" echo "::: If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'" fi if [[ "${core_update}" == true ]]; then pihole_version_current="$(/usr/local/bin/pihole version --pihole --current)" echo ":::" - echo "::: Pi-hole version is now at ${pihole_version_current}" + echo "::: Pi-hole version is now at ${pihole_version_current/* v/v}}" echo "::: If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'" fi if [[ ${FTL_update} == true ]]; then - FTL_version_current="$(/usr/bin/pihole-FTL tag)" + FTL_version_current="$(/usr/local/bin/pihole version --ftl --current)" echo ":::" - echo "::: FTL version is now at ${FTL_version_current}" + echo "::: FTL version is now at ${FTL_version_current/* v/v}}" start_service pihole-FTL enable_service pihole-FTL fi diff --git a/advanced/Scripts/version.sh b/advanced/Scripts/version.sh index 7f96e29a..f5e0f51d 100755 --- a/advanced/Scripts/version.sh +++ b/advanced/Scripts/version.sh @@ -3,24 +3,29 @@ # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. # -# shows version numbers +# Show version numbers # # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. # Variables DEFAULT="-1" -PHGITDIR="/etc/.pihole/" +COREGITDIR="/etc/.pihole/" WEBGITDIR="/var/www/html/admin/" getLocalVersion() { + # FTL requires a different method + if [[ "$1" == "FTL" ]]; then + pihole-FTL version + return 0 + fi + # Get the tagged version of the local repository local directory="${1}" local version - cd "${directory}" || { echo "${DEFAULT}"; return 1; } - version=$(git describe --tags --always || \ - echo "${DEFAULT}") + cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; } + version=$(git describe --tags --always || echo "$DEFAULT") if [[ "${version}" =~ ^v ]]; then echo "${version}" elif [[ "${version}" == "${DEFAULT}" ]]; then @@ -33,13 +38,18 @@ getLocalVersion() { } getLocalHash() { + # Local FTL hash does not exist on filesystem + if [[ "$1" == "FTL" ]]; then + echo "N/A" + return 0 + fi + # Get the short hash of the local repository local directory="${1}" local hash - cd "${directory}" || { echo "${DEFAULT}"; return 1; } - hash=$(git rev-parse --short HEAD || \ - echo "${DEFAULT}") + cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; } + hash=$(git rev-parse --short HEAD || echo "$DEFAULT") if [[ "${hash}" == "${DEFAULT}" ]]; then echo "ERROR" return 1 @@ -49,12 +59,33 @@ getLocalHash() { return 0 } +getRemoteHash(){ + # Remote FTL hash is not applicable + if [[ "$1" == "FTL" ]]; then + echo "N/A" + return 0 + fi + + local daemon="${1}" + local branch="${2}" + + hash=$(git ls-remote --heads "https://github.com/pi-hole/${daemon}" | \ + awk -v bra="$branch" '$0~bra {print substr($0,0,8);exit}') + if [[ -n "$hash" ]]; then + echo "$hash" + else + echo "ERROR" + return 1 + fi + return 0 +} + getRemoteVersion(){ # Get the version from the remote origin local daemon="${1}" local version - version=$(curl --silent --fail https://api.github.com/repos/pi-hole/${daemon}/releases/latest | \ + version=$(curl --silent --fail "https://api.github.com/repos/pi-hole/${daemon}/releases/latest" | \ awk -F: '$1 ~/tag_name/ { print $2 }' | \ tr -cd '[[:alnum:]]._-') if [[ "${version}" =~ ^v ]]; then @@ -66,72 +97,72 @@ getRemoteVersion(){ return 0 } -#PHHASHLATEST=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/commits/master | \ -# grep sha | \ -# head -n1 | \ -# awk -F ' ' '{ print $2 }' | \ -# tr -cd '[[:alnum:]]._-') - -#WEBHASHLATEST=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/commits/master | \ -# grep sha | \ -# head -n1 | \ -# awk -F ' ' '{ print $2 }' | \ -# tr -cd '[[:alnum:]]._-') - - -normalOutput() { - echo "::: Pi-hole version is $(getLocalVersion "${PHGITDIR}") (Latest version is $(getRemoteVersion pi-hole))" - if [ -d "${WEBGITDIR}" ]; then - echo "::: Web-Admin version is $(getLocalVersion "${WEBGITDIR}") (Latest version is $(getRemoteVersion AdminLTE))" - fi -} - -webOutput() { - if [ -d "${WEBGITDIR}" ]; then - case "${1}" in - "-l" | "--latest" ) echo $(getRemoteVersion AdminLTE);; - "-c" | "--current" ) echo $(getLocalVersion "${WEBGITDIR}");; - "-h" | "--hash" ) echo $(getLocalHash "${WEBGITDIR}");; - * ) echo "::: Invalid Option!"; exit 1; - esac - else - echo "::: Web interface not installed!"; exit 1; +versionOutput() { + [[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR + [[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR + [[ "$1" == "FTL" ]] && GITDIR="FTL" + + [[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $GITDIR) + [[ "$2" == "-l" ]] || [[ "$2" == "--latest" ]] || [[ -z "$2" ]] && latest=$(getRemoteVersion "$1") + if [[ "$2" == "-h" ]] || [[ "$2" == "--hash" ]]; then + [[ "$3" == "-c" ]] || [[ "$3" == "--current" ]] || [[ -z "$3" ]] && curHash=$(getLocalHash "$GITDIR") + [[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)") fi + + if [[ -n "$current" ]] && [[ -n "$latest" ]]; then + output="${1^} version is $current (Latest: $latest)" + elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then + output="Current ${1^} version is $current" + elif [[ -z "$current" ]] && [[ -n "$latest" ]]; then + output="Latest ${1^} version is $latest" + elif [[ "$curHash" == "N/A" ]] || [[ "$latHash" == "N/A" ]]; then + output="${1^} hash is not applicable" + elif [[ -n "$curHash" ]] && [[ -n "$latHash" ]]; then + output="${1^} hash is $curHash (Latest: $latHash)" + elif [[ -n "$curHash" ]] && [[ -z "$latHash" ]]; then + output="Current ${1^} hash is $curHash" + elif [[ -z "$curHash" ]] && [[ -n "$latHash" ]]; then + output="Latest ${1^} hash is $latHash" + else + errorOutput + fi + + [[ -n "$output" ]] && echo " $output" } -coreOutput() { - case "${1}" in - "-l" | "--latest" ) echo $(getRemoteVersion pi-hole);; - "-c" | "--current" ) echo $(getLocalVersion "${PHGITDIR}");; - "-h" | "--hash" ) echo $(getLocalHash "${PHGITDIR}");; - * ) echo "::: Invalid Option!"; exit 1; - esac +errorOutput() { + echo " Invalid Option! Try 'pihole -v --help' for more information." + exit 1 +} + +defaultOutput() { + versionOutput "pi-hole" "$@" + versionOutput "AdminLTE" "$@" + versionOutput "FTL" "$@" } 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 0 + echo "Usage: pihole -v [repo | option] [option] +Example: 'pihole -v -p -l' +Show Pi-hole, Admin Console & FTL versions + +Repositories: + -p, --pihole Only retrieve info regarding Pi-hole repository + -a, --admin Only retrieve info regarding AdminLTE repository + -f, --ftl Only retrieve info regarding FTL repository + +Options: + -c, --current Return the current version + -l, --latest Return the latest version + --hash Return the Github hash from your local repositories + -h, --help Show this help dialog" + exit 0 } -if [[ $# = 0 ]]; then - normalOutput -fi - case "${1}" in - "-a" | "--admin" ) shift; webOutput "$@";; - "-p" | "--pihole" ) shift; coreOutput "$@" ;; + "-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";; + "-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";; + "-f" | "--ftl" ) shift; versionOutput "FTL" "$@";; "-h" | "--help" ) helpFunc;; + * ) defaultOutput "$@";; esac diff --git a/advanced/Scripts/webpage.sh b/advanced/Scripts/webpage.sh index d3ad3032..8419aa8d 100755 --- a/advanced/Scripts/webpage.sh +++ b/advanced/Scripts/webpage.sh @@ -8,7 +8,6 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. - readonly setupVars="/etc/pihole/setupVars.conf" readonly dnsmasqconfig="/etc/dnsmasq.d/01-pihole.conf" readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf" @@ -16,23 +15,19 @@ readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf" readonly dhcpstaticconfig="/etc/dnsmasq.d/04-pihole-static-dhcp.conf" helpFunc() { - cat << EOM -::: Set admin options for the web interface of pihole -::: -::: Usage: pihole -a [options] -::: -::: Options: -::: -p, password Set web interface password, an empty input will remove any previously set password -::: -c, celsius Set Celsius temperature unit -::: -f, fahrenheit Set Fahrenheit temperature unit -::: -k, kelvin Set Kelvin temperature unit -::: -h, --help Show this help dialog -::: -i, interface Setup interface listening behavior of dnsmasq -::: pihole -a -i local : Listen on all interfaces, but allow only queries from -::: devices that are at most one hop away (local devices) -::: pihole -a -i single : Listen only on one interface (see PIHOLE_INTERFACE) -::: pihole -a -i all : Listen on all interfaces, permit all origins -EOM + echo "Usage: pihole -a [options] +Example: pihole -a -p password +Set options for the Admin Console + +Options: + -f, flush Flush the Pi-hole log + -p, password Set Admin Console password + -c, celsius Set Celsius as preferred temperature unit + -f, fahrenheit Set Fahrenheit as preferred temperature unit + -k, kelvin Set Kelvin as preferred temperature unit + -h, --help Show this help dialog + -i, interface Specify dnsmasq's interface listening behavior + Add '-h' for more info on interface usage" exit 0 } @@ -61,21 +56,18 @@ delete_dnsmasq_setting() { sed -i "/${1}/d" "${dnsmasqconfig}" } -SetTemperatureUnit(){ - +SetTemperatureUnit() { change_setting "TEMPERATUREUNIT" "${unit}" - } -HashPassword(){ - # Compute password hash twice to avoid rainbow table vulnerability - return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//') - return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//') - echo ${return} +HashPassword() { + # Compute password hash twice to avoid rainbow table vulnerability + return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//') + return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//') + echo ${return} } -SetWebPassword(){ - +SetWebPassword() { if [ "${SUDO_USER}" == "www-data" ]; then echo "Security measure: user www-data is not allowed to change webUI password!" echo "Exiting" @@ -175,8 +167,7 @@ trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE3 } -SetDNSServers(){ - +SetDNSServers() { # Save setting to file delete_setting "PIHOLE_DNS" IFS=',' read -r -a array <<< "${args[2]}" @@ -207,72 +198,59 @@ SetDNSServers(){ # Restart dnsmasq to load new configuration RestartDNS - } -SetExcludeDomains(){ - +SetExcludeDomains() { change_setting "API_EXCLUDE_DOMAINS" "${args[2]}" - } -SetExcludeClients(){ - +SetExcludeClients() { change_setting "API_EXCLUDE_CLIENTS" "${args[2]}" - } -Reboot(){ - +Reboot() { nohup bash -c "sleep 5; reboot" &> /dev/null /dev/null else service dnsmasq restart &> /dev/null fi - } -SetQueryLogOptions(){ - +SetQueryLogOptions() { change_setting "API_QUERY_LOG_SHOW" "${args[2]}" - } ProcessDHCPSettings() { - source "${setupVars}" if [[ "${DHCP_ACTIVE}" == "true" ]]; then + interface=$(grep 'PIHOLE_INTERFACE=' /etc/pihole/setupVars.conf | sed "s/.*=//") - interface=$(grep 'PIHOLE_INTERFACE=' /etc/pihole/setupVars.conf | sed "s/.*=//") + # Use eth0 as fallback interface + if [ -z ${interface} ]; then + interface="eth0" + fi - # Use eth0 as fallback interface - if [ -z ${interface} ]; then - interface="eth0" - fi + if [[ "${PIHOLE_DOMAIN}" == "" ]]; then + PIHOLE_DOMAIN="local" + change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}" + fi - if [[ "${PIHOLE_DOMAIN}" == "" ]]; then - PIHOLE_DOMAIN="local" - change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}" - fi + if [[ "${DHCP_LEASETIME}" == "0" ]]; then + leasetime="infinite" + elif [[ "${DHCP_LEASETIME}" == "" ]]; then + leasetime="24h" + change_setting "DHCP_LEASETIME" "${leasetime}" + else + leasetime="${DHCP_LEASETIME}h" + fi - if [[ "${DHCP_LEASETIME}" == "0" ]]; then - leasetime="infinite" - elif [[ "${DHCP_LEASETIME}" == "" ]]; then - leasetime="24h" - change_setting "DHCP_LEASETIME" "${leasetime}" - else - leasetime="${DHCP_LEASETIME}h" - fi - - # Write settings to file - echo "############################################################################### + # Write settings to file + echo "############################################################################### # DHCP SERVER CONFIG FILE AUTOMATICALLY POPULATED BY PI-HOLE WEB INTERFACE. # # ANY CHANGES MADE TO THIS FILE WILL BE LOST ON CHANGE # ############################################################################### @@ -283,26 +261,25 @@ dhcp-leasefile=/etc/pihole/dhcp.leases #quiet-dhcp " > "${dhcpconfig}" -if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then - echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}" -fi + if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then + echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}" + fi - if [[ "${DHCP_IPv6}" == "true" ]]; then -echo "#quiet-dhcp6 + if [[ "${DHCP_IPv6}" == "true" ]]; then + echo "#quiet-dhcp6 #enable-ra dhcp-option=option6:dns-server,[::] dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,${leasetime} ra-param=*,0,0 " >> "${dhcpconfig}" - fi + fi else rm "${dhcpconfig}" &> /dev/null fi } -EnableDHCP(){ - +EnableDHCP() { change_setting "DHCP_ACTIVE" "true" change_setting "DHCP_START" "${args[2]}" change_setting "DHCP_END" "${args[3]}" @@ -320,8 +297,7 @@ EnableDHCP(){ RestartDNS } -DisableDHCP(){ - +DisableDHCP() { change_setting "DHCP_ACTIVE" "false" # Remove possible old setting from file @@ -333,23 +309,20 @@ DisableDHCP(){ RestartDNS } -SetWebUILayout(){ - +SetWebUILayout() { change_setting "WEBUIBOXEDLAYOUT" "${args[2]}" - } CustomizeAdLists() { - list="/etc/pihole/adlists.list" - if [[ "${args[2]}" == "enable" ]] ; then + if [[ "${args[2]}" == "enable" ]]; then sed -i "\\@${args[3]}@s/^#http/http/g" "${list}" - elif [[ "${args[2]}" == "disable" ]] ; then + elif [[ "${args[2]}" == "disable" ]]; then sed -i "\\@${args[3]}@s/^http/#http/g" "${list}" - elif [[ "${args[2]}" == "add" ]] ; then + elif [[ "${args[2]}" == "add" ]]; then echo "${args[3]}" >> ${list} - elif [[ "${args[2]}" == "del" ]] ; then + elif [[ "${args[2]}" == "del" ]]; then var=$(echo "${args[3]}" | sed 's/\//\\\//g') sed -i "/${var}/Id" "${list}" else @@ -358,18 +331,15 @@ CustomizeAdLists() { fi } -SetPrivacyMode(){ - - if [[ "${args[2]}" == "true" ]] ; then +SetPrivacyMode() { + if [[ "${args[2]}" == "true" ]]; then change_setting "API_PRIVACY_MODE" "true" else change_setting "API_PRIVACY_MODE" "false" fi - } ResolutionSettings() { - typ="${args[2]}" state="${args[3]}" @@ -378,11 +348,9 @@ ResolutionSettings() { elif [[ "${typ}" == "clients" ]]; then change_setting "API_GET_CLIENT_HOSTNAME" "${state}" fi - } AddDHCPStaticAddress() { - mac="${args[2]}" ip="${args[3]}" host="${args[4]}" @@ -397,18 +365,14 @@ AddDHCPStaticAddress() { # Full info given echo "dhcp-host=${mac},${ip},${host}" >> "${dhcpstaticconfig}" fi - } RemoveDHCPStaticAddress() { - mac="${args[2]}" sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}" - } -SetHostRecord(){ - +SetHostRecord() { if [ -n "${args[3]}" ]; then change_setting "HOSTRECORD" "${args[2]},${args[3]}" echo "Setting host record for ${args[2]} -> ${args[3]}" @@ -421,17 +385,28 @@ SetHostRecord(){ # Restart dnsmasq to load new configuration RestartDNS - } -SetListeningMode(){ - +SetListeningMode() { source "${setupVars}" + + if [[ "$3" == "-h" ]] || [[ "$3" == "--help" ]]; then + echo "Usage: pihole -a -i [interface] +Example: 'pihole -a -i local' +Specify dnsmasq's network interface listening behavior - if [[ "${args[2]}" == "all" ]] ; then +Interfaces: + local Listen on all interfaces, but only allow queries from + devices that are at most one hop away (local devices) + single Listen only on ${PIHOLE_INTERFACE} interface + all Listen on all interfaces, permit all origins" + exit 0 + fi + + if [[ "${args[2]}" == "all" ]]; then echo "Listening on all interfaces, permiting all origins, hope you have a firewall!" change_setting "DNSMASQ_LISTENING" "all" - elif [[ "${args[2]}" == "local" ]] ; then + elif [[ "${args[2]}" == "local" ]]; then echo "Listening on all interfaces, permitting only origins that are at most one hop away (local devices)" change_setting "DNSMASQ_LISTENING" "local" else @@ -446,17 +421,14 @@ SetListeningMode(){ # Restart dnsmasq to load new configuration RestartDNS fi - } -Teleporter() -{ +Teleporter() { local datetimestamp=$(date "+%Y-%m-%d_%H-%M-%S") php /var/www/html/admin/scripts/pi-hole/php/teleporter.php > "pi-hole-teleporter_${datetimestamp}.zip" } main() { - args=("$@") case "${args[1]}" in @@ -479,7 +451,7 @@ main() { "addstaticdhcp" ) AddDHCPStaticAddress;; "removestaticdhcp" ) RemoveDHCPStaticAddress;; "hostrecord" ) SetHostRecord;; - "-i" | "interface" ) SetListeningMode;; + "-i" | "interface" ) SetListeningMode "$@";; "-t" | "teleporter" ) Teleporter;; "adlist" ) CustomizeAdLists;; * ) helpFunc;; @@ -490,5 +462,4 @@ main() { if [[ $# = 0 ]]; then helpFunc fi - } diff --git a/advanced/index.php b/advanced/index.php index bfc44a1d..1dd5acc7 100644 --- a/advanced/index.php +++ b/advanced/index.php @@ -185,7 +185,7 @@ function add() { } $.ajax({ - url: "admin/scripts/pi-hole/php/add.php", + url: "/admin/scripts/pi-hole/php/add.php", method: "post", data: {"domain":domain.val(), "list":"white", "pw":pw.val()}, success: function(response) { diff --git a/advanced/logrotate b/advanced/logrotate index 570e7548..ffed910b 100644 --- a/advanced/logrotate +++ b/advanced/logrotate @@ -8,3 +8,14 @@ notifempty nomail } + +/var/log/pihole-FTL.log { + # su # + weekly + copytruncate + rotate 3 + compress + delaycompress + notifempty + nomail +} diff --git a/advanced/pihole-FTL.service b/advanced/pihole-FTL.service index 30cd140f..627fad8c 100644 --- a/advanced/pihole-FTL.service +++ b/advanced/pihole-FTL.service @@ -26,7 +26,7 @@ start() { echo "pihole-FTL is already running" else touch /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port - chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port + chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /etc/pihole chmod 0644 /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port su -s /bin/sh -c "/usr/bin/pihole-FTL" "$FTLUSER" echo diff --git a/advanced/pihole.cron b/advanced/pihole.cron index c885b371..f1beb08c 100644 --- a/advanced/pihole.cron +++ b/advanced/pihole.cron @@ -21,9 +21,10 @@ # Pi-hole: Update Pi-hole! Uncomment to enable auto update #30 2 * * 7 root PATH="$PATH:/usr/local/bin/" pihole updatePihole -# 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 +# Pi-hole: Flush the log daily at 00:00 # The flush script will use logrotate if available -00 00 * * * root PATH="$PATH:/usr/local/bin/" pihole flush +# parameter "once": logrotate only once (default is twice) +# parameter "quiet": don't print messages +00 00 * * * root PATH="$PATH:/usr/local/bin/" pihole flush once quiet @reboot root /usr/sbin/logrotate /etc/pihole/logrotate diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index c65ef49f..053e04ba 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -86,7 +86,7 @@ if command -v apt-get &> /dev/null; then #Debian Family ############################################# PKG_MANAGER="apt-get" - UPDATE_PKG_CACHE="test_dpkg_lock; ${PKG_MANAGER} update" + UPDATE_PKG_CACHE="${PKG_MANAGER} update" PKG_INSTALL=(${PKG_MANAGER} --yes --no-install-recommends 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" @@ -220,6 +220,16 @@ getGitFiles() { return 0 } +resetRepo() { + local directory="${1}" + + cd "${directory}" &> /dev/null || return 1 + echo -n "::: Resetting repo in ${1}..." + git reset --hard &> /dev/null || return $? + echo " done!" + return 0 +} + find_IPv4_information() { local route # Find IP used to route to outside world @@ -317,16 +327,44 @@ chooseInterface() { fi } +# See https://github.com/pi-hole/pi-hole/issues/1473#issuecomment-301745953 +testIPv6() { + first="$(cut -f1 -d":" <<< "$1")" + value1=$(((0x$first)/256)) + value2=$(((0x$first)%256)) + ((($value1&254)==252)) && echo "ULA" || true + ((($value1&112)==32)) && echo "GUA" || true + ((($value1==254) && (($value2&192)==128))) && echo "Link-local" || true +} + useIPv6dialog() { - # Show the IPv6 address used for blocking - IPV6_ADDRESS=$(ip -6 route get 2001:4860:4860::8888 | grep -v "unreachable" | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "src") print $(i+1) }') + # Determine the IPv6 address used for blocking + IPV6_ADDRESSES=($(ip -6 address | grep 'scope global' | awk '{print $2}')) + + # Determine type of found IPv6 addresses + for i in "${IPV6_ADDRESSES[@]}"; do + result=$(testIPv6 "$i") + [[ "${result}" == "ULA" ]] && ULA_ADDRESS="$i" + [[ "${result}" == "GUA" ]] && GUA_ADDRESS="$i" + done + + # Determine which address to be used: Prefer ULA over GUA or don't use any if none found + if [[ ! -z "${ULA_ADDRESS}" ]]; then + IPV6_ADDRESS="${ULA_ADDRESS}" + echo "::: Found IPv6 ULA address, using it for blocking IPv6 ads" + elif [[ ! -z "${GUA_ADDRESS}" ]]; then + echo "::: Found IPv6 GUA address, using it for blocking IPv6 ads" + IPV6_ADDRESS="${GUA_ADDRESS}" + else + echo "::: Found neither IPv6 ULA nor GUA address, blocking IPv6 ads will not be enabled" + IPV6_ADDRESS="" + fi if [[ ! -z "${IPV6_ADDRESS}" ]]; then whiptail --msgbox --backtitle "IPv6..." --title "IPv6 Supported" "$IPV6_ADDRESS will be used to block ads." ${r} ${c} fi } - use4andor6() { local useIPv4 local useIPv6 @@ -408,7 +446,7 @@ setDHCPCD() { echo "interface ${PIHOLE_INTERFACE} static ip_address=${IPV4_ADDRESS} static routers=${IPv4gw} - static domain_name_servers=${IPv4gw}" | tee -a /etc/dhcpcd.conf >/dev/null + static domain_name_servers=127.0.0.1" | tee -a /etc/dhcpcd.conf >/dev/null } setStaticIPv4() { @@ -980,6 +1018,7 @@ configureFirewall() { iptables -C INPUT -p tcp -m tcp --dport 80 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT iptables -C INPUT -p tcp -m tcp --dport 53 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT iptables -C INPUT -p udp -m udp --dport 53 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT + iptables -C INPUT -p tcp -m tcp --dport 4711:4720 -i lo -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 4711:4720 -i lo -j ACCEPT return 0 fi else @@ -1041,7 +1080,7 @@ installLogrotate() { # the local properties of the /var/log directory logusergroup="$(stat -c '%U %G' /var/log)" if [[ ! -z $logusergroup ]]; then - sed -i "s/# su #/su ${logusergroup}/" /etc/pihole/logrotate + sed -i "s/# su #/su ${logusergroup}/g;" /etc/pihole/logrotate fi echo " done!" } @@ -1128,10 +1167,18 @@ checkSelinux() { displayFinalMessage() { + if [[ ${#1} -gt 0 ]] ; then + pwstring="$1" + elif [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) -gt 0 ]]; then + pwstring="unchanged" + else + pwstring="NOT SET" + fi + if [[ ${INSTALL_WEB} == true ]]; then additional="View the web interface at http://pi.hole/admin or http://${IPV4_ADDRESS%/*}/admin -Your Admin Webpage login password is ${1:-"NOT SET"}" +Your Admin Webpage login password is ${pwstring}" fi # Final completion message to user @@ -1179,22 +1226,32 @@ update_dialogs() { } clone_or_update_repos() { -if [[ "${reconfigure}" == true ]]; then - echo "::: --reconfigure passed to install script. Not downloading/updating local repos" - else - # Get Git files for Core and Admin - getGitFiles ${PI_HOLE_LOCAL_REPO} ${piholeGitUrl} || \ - { echo "!!! Unable to clone ${piholeGitUrl} into ${PI_HOLE_LOCAL_REPO}, unable to continue."; \ + if [[ "${reconfigure}" == true ]]; then + echo "::: --reconfigure passed to install script. Resetting changes to local repos" + resetRepo ${PI_HOLE_LOCAL_REPO} || \ + { echo "!!! Unable to reset ${PI_HOLE_LOCAL_REPO}, unable to continue."; \ + exit 1; \ + } + if [[ ${INSTALL_WEB} == true ]]; then + resetRepo ${webInterfaceDir} || \ + { echo "!!! Unable to reset ${webInterfaceDir}, unable to continue."; \ exit 1; \ } - - if [[ ${INSTALL_WEB} == true ]]; then - getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl} || \ - { echo "!!! Unable to clone ${webInterfaceGitUrl} into ${webInterfaceDir}, unable to continue."; \ - exit 1; \ - } - fi fi + else + # Get Git files for Core and Admin + getGitFiles ${PI_HOLE_LOCAL_REPO} ${piholeGitUrl} || \ + { echo "!!! Unable to clone ${piholeGitUrl} into ${PI_HOLE_LOCAL_REPO}, unable to continue."; \ + exit 1; \ + } + + if [[ ${INSTALL_WEB} == true ]]; then + getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl} || \ + { echo "!!! Unable to clone ${webInterfaceGitUrl} into ${webInterfaceDir}, unable to continue."; \ + exit 1; \ + } + fi + fi } FTLinstall() { @@ -1220,6 +1277,7 @@ FTLinstall() { echo -n "transferred... " stop_service pihole-FTL &> /dev/null install -T -m 0755 /tmp/${binary} /usr/bin/pihole-FTL + rm /tmp/${binary} /tmp/${binary}.sha1 cd "${orig_dir}" install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/pihole-FTL.service" "/etc/init.d/pihole-FTL" echo "done." diff --git a/gravity.sh b/gravity.sh index a5231d5e..285ce5c3 100755 --- a/gravity.sh +++ b/gravity.sh @@ -54,6 +54,7 @@ IPV6_ADDRESS=${IPV6_ADDRESS} basename=pihole piholeDir=/etc/${basename} adList=${piholeDir}/gravity.list +blackList=${piholeDir}/black.list localList=${piholeDir}/local.list justDomainsExtension=domains matterAndLight=${basename}.0.matterandlight.txt @@ -235,9 +236,7 @@ gravity_Blacklist() { 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!" + echo "::: Exact blocked domain${plural}: $numBlacklisted" else echo "::: Nothing to blacklist!" fi @@ -299,9 +298,25 @@ gravity_unique() { echo "::: $numberOf unique domains trapped in the event horizon." } -gravity_hostFormat() { +gravity_doHostFormat() { + # 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 + awk -v ipv4addr="$IPV4_ADDRESS" -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> "${2}" < "${1}" + elif [[ -n "${IPV4_ADDRESS}" && -z "${IPV6_ADDRESS}" ]];then + # Only IPv4 + awk -v ipv4addr="$IPV4_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0}' >> "${2}" < "${1}" + elif [[ -z "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then + # Only IPv6 + awk -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv6addr" "$0}' >> "${2}" < "${1}" + 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 +} + +gravity_hostFormatLocal() { # Format domain list as "192.168.x.x domain.com" - echo -n "::: Formatting domains into a HOSTS file..." if [[ -f /etc/hostname ]]; then hostname=$( ${localList} - # 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 - - echo -e "${IPV4_ADDRESS} ${hostname}\n${IPV4_ADDRESS} pi.hole" > ${localList} - # 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 - - echo -e "${IPV6_ADDRESS} ${hostname}\n${IPV6_ADDRESS} pi.hole" > ${localList} - # 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 + echo -e "${hostname}\npi.hole" > "${localList}.tmp" + # Copy the file over as /etc/pihole/local.list so dnsmasq can use it + rm "${localList}" + gravity_doHostFormat "${localList}.tmp" "${localList}" + rm "${localList}.tmp" +} +gravity_hostFormatGravity() { + # Format domain list as "192.168.x.x domain.com" + echo "" > "${piholeDir}/${accretionDisc}" + gravity_doHostFormat "${piholeDir}/${eventHorizon}" "${piholeDir}/${accretionDisc}" # Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it - cp ${piholeDir}/${accretionDisc} ${adList} - echo " done!" + mv "${piholeDir}/${accretionDisc}" "${adList}" +} + +gravity_hostFormatBlack() { + if [[ -f "${blacklistFile}" ]]; then + numBlacklisted=$(wc -l < "${blacklistFile}") + # Format domain list as "192.168.x.x domain.com" + gravity_doHostFormat "${blacklistFile}" "${blackList}.tmp" + # Copy the file over as /etc/pihole/black.list so dnsmasq can use it + mv "${blackList}.tmp" "${blackList}" + else + echo "::: Nothing to blacklist!" + fi } # blackbody - remove any remnant files from script processes @@ -377,11 +391,6 @@ gravity_advanced() { } gravity_reload() { - #Clear no longer needed files... - echo ":::" - echo -n "::: Cleaning up un-needed files..." - rm ${piholeDir}/pihole.*.txt - echo " done!" # Reload hosts file echo ":::" @@ -402,6 +411,7 @@ for var in "$@"; do "-f" | "--force" ) forceGrav=true;; "-h" | "--help" ) helpFunc;; "-sd" | "--skip-download" ) skipDownload=true;; + "-b" | "--blacklist-only" ) blackListOnly=true;; esac done @@ -411,22 +421,39 @@ if [[ "${forceGrav}" == true ]]; then echo " done!" fi -gravity_collapse -gravity_spinup -if [[ "${skipDownload}" == false ]]; then +if [[ ! "${blackListOnly}" == true ]]; then + gravity_collapse + gravity_spinup + if [[ "${skipDownload}" == false ]]; then gravity_Schwarzchild gravity_advanced -else + else echo "::: Using cached Event Horizon list..." numberOf=$(wc -l < ${piholeDir}/${preEventHorizon}) - echo "::: $numberOf unique domains trapped in the event horizon." + echo "::: $numberOf unique domains trapped in the event horizon." + fi + gravity_Whitelist fi -gravity_Whitelist gravity_Blacklist gravity_Wildcard -gravity_hostFormat +echo -n "::: Formatting domains into a HOSTS file..." +if [[ ! "${blackListOnly}" == true ]]; then + gravity_hostFormatLocal + gravity_hostFormatGravity +fi +gravity_hostFormatBlack +echo " done!" + gravity_blackbody +if [[ ! "${blackListOnly}" == true ]]; then + #Clear no longer needed files... + echo ":::" + echo -n "::: Cleaning up un-needed files..." + rm ${piholeDir}/pihole.*.txt + echo " done!" +fi + gravity_reload "${PIHOLE_COMMAND}" status diff --git a/pihole b/pihole index 83e13000..055d6bce 100755 --- a/pihole +++ b/pihole @@ -9,11 +9,11 @@ # Please see LICENSE file for your rights under this license. readonly PI_HOLE_SCRIPT_DIR="/opt/pihole" - readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf" + # Must be root to use this tool if [[ ! $EUID -eq 0 ]];then - if [ -x "$(command -v sudo)" ];then + if [[ -x "$(command -v sudo)" ]]; then exec sudo bash "$0" "$@" exit $? else @@ -61,7 +61,7 @@ debugFunc() { } flushFunc() { - "${PI_HOLE_SCRIPT_DIR}"/piholeLogFlush.sh + "${PI_HOLE_SCRIPT_DIR}"/piholeLogFlush.sh "$@" exit 0 } @@ -163,16 +163,16 @@ versionFunc() { restartDNS() { dnsmasqPid=$(pidof dnsmasq) - if [[ ${dnsmasqPid} ]]; then - # service already running - reload config - if [ -x "$(command -v systemctl)" ]; then + if [[ "${dnsmasqPid}" ]]; then + # Service already running - reload config + if [[ -x "$(command -v systemctl)" ]]; then systemctl restart dnsmasq else service dnsmasq restart fi else - # service not running, start it up - if [ -x "$(command -v systemctl)" ]; then + # Service not running, start it up + if [[ -x "$(command -v systemctl)" ]]; then systemctl start dnsmasq else service dnsmasq start @@ -181,16 +181,29 @@ restartDNS() { } piholeEnable() { - if [[ "${1}" == "0" ]] ; then - #Disable Pihole + if [[ "${2}" == "-h" ]] || [[ "${2}" == "--help" ]]; then + echo "Usage: pihole disable [time] +Example: 'pihole disable', or 'pihole disable 5m' +Disable Pi-hole subsystems + +Time: + #s Disable Pi-hole functionality for # second(s) + #m Disable Pi-hole functionality for # minute(s)" + exit 0 + elif [[ "${1}" == "0" ]]; then + # Disable Pi-hole sed -i 's/^addn-hosts=\/etc\/pihole\/gravity.list/#addn-hosts=\/etc\/pihole\/gravity.list/' /etc/dnsmasq.d/01-pihole.conf + sed -i 's/^addn-hosts=\/etc\/pihole\/black.list/#addn-hosts=\/etc\/pihole\/black.list/' /etc/dnsmasq.d/01-pihole.conf + if [[ -e "$wildcardlist" ]]; then + mv "$wildcardlist" "/etc/pihole/wildcard.list" + fi echo "::: Blocking has been disabled!" - if [[ $# > 1 ]] ; then - if [[ ${2} == *"s"* ]] ; then + if [[ $# > 1 ]]; then + if [[ "${2}" == *"s"* ]]; then tt=${2%"s"} echo "::: Blocking will be re-enabled in ${tt} seconds" nohup bash -c "sleep ${tt}; pihole enable" /dev/null & - elif [[ ${2} == *"m"* ]] ; then + elif [[ "${2}" == *"m"* ]]; then tt=${2%"m"} echo "::: Blocking will be re-enabled in ${tt} minutes" tt=$((${tt}*60)) @@ -204,24 +217,35 @@ piholeEnable() { fi fi else - #Enable pihole + # Enable Pi-hole echo "::: Blocking has been enabled!" sed -i 's/^#addn-hosts/addn-hosts/' /etc/dnsmasq.d/01-pihole.conf + if [[ -e "/etc/pihole/wildcard.list" ]]; then + mv "/etc/pihole/wildcard.list" "$wildcardlist" + fi fi restartDNS } piholeLogging() { shift + if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then + echo "Usage: pihole logging [options] +Example: 'pihole logging on' +Specify whether the Pi-hole log should be used - if [[ "${1}" == "off" ]] ; then - #Disable Logging +Options: + on Enable the Pi-hole log at /var/log/pihole.log + off Disable the Pi-hole log at /var/log/pihole.log" + exit 0 + elif [[ "${1}" == "off" ]]; then + # Disable logging sed -i 's/^log-queries/#log-queries/' /etc/dnsmasq.d/01-pihole.conf sed -i 's/^QUERY_LOGGING=true/QUERY_LOGGING=false/' /etc/pihole/setupVars.conf pihole -f echo "::: Logging has been disabled!" - elif [[ "${1}" == "on" ]] ; then - #Enable logging + elif [[ "${1}" == "on" ]]; then + # Enable logging sed -i 's/^#log-queries/log-queries/' /etc/dnsmasq.d/01-pihole.conf sed -i 's/^QUERY_LOGGING=false/QUERY_LOGGING=true/' /etc/pihole/setupVars.conf echo "::: Logging has been enabled!" @@ -233,12 +257,12 @@ piholeLogging() { } piholeStatus() { - if [[ $(netstat -plnt | grep -c ':53 ') > 0 ]]; then - if [[ "${1}" != "web" ]] ; then + if [[ "$(netstat -plnt | grep -c ':53 ')" -gt "0" ]]; then + if [[ "${1}" != "web" ]]; then echo "::: DNS service is running" fi else - if [[ "${1}" == "web" ]] ; then + if [[ "${1}" == "web" ]]; then echo "-1"; else echo "::: DNS service is NOT running" @@ -246,28 +270,28 @@ piholeStatus() { return fi - if [[ $(grep -i "^#addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf) ]] ; then - #list is commented out - if [[ "${1}" == "web" ]] ; then + if [[ "$(grep -i "^#addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf)" ]]; then + # List is commented out + if [[ "${1}" == "web" ]]; then echo 0; else echo "::: Pi-hole blocking is Disabled"; fi - elif [[ $(grep -i "^addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf) ]] ; then - #list set - if [[ "${1}" == "web" ]] ; then + elif [[ "$(grep -i "^addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf)" ]]; 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 + # 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 + # Add addn-host= to dnsmasq echo "addn-hosts=/etc/pihole/gravity.list" >> /etc/dnsmasq.d/01-pihole.conf restartDNS fi @@ -280,46 +304,96 @@ tailFunc() { } piholeCheckoutFunc() { + if [[ "$2" == "-h" ]] || [[ "$2" == "--help" ]]; then + echo "Usage: pihole checkout [repo] [branch] +Example: 'pihole checkout master' or 'pihole checkout core dev' +Switch Pi-hole subsystems to a different Github branch + +Repositories: + core [branch] Change the branch of Pi-hole's core subsystem + web [branch] Change the branch of Admin Console subsystem + +Branches: + master Update subsystems to the latest stable release + dev Update subsystems to the latest development release" + exit 0 + fi + source "${PI_HOLE_SCRIPT_DIR}"/piholeCheckout.sh shift checkout "$@" } +tricorderFunc() { + if [[ ! -p "/dev/stdin" ]]; then + echo "Please do not call Tricorder directly." + exit 1 + fi + + if ! timeout 2 nc -z tricorder.pi-hole.net 9998 &> /dev/null; then + echo "Unable to connect to Pi-hole's Tricorder server." + exit 1 + fi + + if command -v openssl &> /dev/null; then + openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin + exit "$?" + else + echo "Your debug log will be transmitted unencrypted via plain-text" + echo "There is a possibility that this could be intercepted by a third party" + echo "If you wish to cancel, press Ctrl-C to exit within 10 seconds" + secs="10" + while [[ "$secs" -gt "0" ]]; do + echo -ne "." + sleep 1 + : $((secs--)) + done + echo " " + nc tricorder.pi-hole.net 9999 < /dev/stdin + exit "$?" + fi +} + helpFunc() { - cat << EOM -::: Control all Pi-hole specific functions -::: -::: Usage: pihole [options] -::: Add -h after -w (whitelist), -b (blacklist), -c (chronometer), or -a (admin) for more information on usage -::: -::: Options: -::: -w, whitelist Whitelist domain(s) -::: -b, blacklist Blacklist domain(s) (exact match) -::: -wild, wildcard Blacklist whole domain(s) (wildcard) -::: -d, debug Start a debugging session -::: Automated debugging can be enabled with '-a'. -::: 'pihole -d -a' -::: -f, flush Flush the 'pihole.log' file -::: -t, tail Output the last lines of the 'pihole.log' file. Lines are appended as the file grows -::: -up, updatePihole Update Pi-hole components -::: -r, reconfigure Reconfigure or Repair Pi-hole -::: -g, updateGravity Update the list of ad-serving domains -::: -c, chronometer Calculates stats and displays to an LCD -::: -h, help Show this help dialog -::: -v, version Show installed versions of Pi-hole and Web-Admin -::: -q, query Query the adlists for a specific domain -::: 'pihole -q domain -exact' shows exact matches only -::: -l, logging Enable or Disable logging (pass 'on' or 'off') -::: -a, admin Admin webpage options -::: uninstall Uninstall Pi-hole from your system! :( -::: status Display if Pi-hole is Enabled or Disabled -::: enable Enable Pi-hole DNS Blocking -::: disable Disable Pi-hole DNS Blocking -::: Blocking can also be disabled only temporarily, e.g., -::: 'pihole disable 5m' - will disable blocking for 5 minutes -::: restartdns Restart dnsmasq -::: checkout Check out different branches -EOM + echo "Usage: pihole [options] +Example: 'pihole -w -h' +Add '-h' after specific commands for more information on usage + +Whitelist/Blacklist Options: + -w, whitelist Whitelist domain(s) + -b, blacklist Blacklist domain(s) + -wild, wildcard Blacklist domain(s), and all its subdomains + Add '-h' for more info on whitelist/blacklist usage + +Debugging Options: + -d, debug Start a debugging session + Add '-a' to enable automated debugging + -f, flush Flush the Pi-hole log + -r, reconfigure Reconfigure or Repair Pi-hole subsystems + -t, tail View the live output of the Pi-hole log + +Options: + -a, admin Admin Console options + Add '-h' for more info on admin console usage + -c, chronometer Calculates stats and displays to an LCD + Add '-h' for more info on chronometer usage + -g, updateGravity Update the list of ad-serving domains + -h, --help, help Show this help dialog + -l, logging Specify whether the Pi-hole log should be used + Add '-h' for more info on logging usage + -q, query Query the adlists for a specified domain + Add '-exact' AFTER a specified domain for exact match + -up, updatePihole Update Pi-hole subsystems + -v, version Show installed versions of Pi-hole, Admin Console & FTL + Add '-h' for more info on version usage + uninstall Uninstall Pi-hole from your system + status Display the running status of Pi-hole subsystems + enable Enable Pi-hole subsystems + disable Disable Pi-hole subsystems + Add '-h' for more info on disable usage + restartdns Restart Pi-hole subsystems + checkout Switch Pi-hole subsystems to a different Github branch + Add '-h' for more info on checkout usage"; exit 0 } @@ -333,7 +407,7 @@ case "${1}" in "-b" | "blacklist" ) blacklistFunc "$@";; "-wild" | "wildcard" ) wildcardFunc "$@";; "-d" | "debug" ) debugFunc "$@";; - "-f" | "flush" ) flushFunc;; + "-f" | "flush" ) flushFunc "$@";; "-up" | "updatePihole" ) updatePiholeFunc;; "-r" | "reconfigure" ) reconfigurePiholeFunc;; "-g" | "updateGravity" ) updateGravityFunc "$@";; @@ -344,11 +418,12 @@ case "${1}" in "-l" | "logging" ) piholeLogging "$@";; "uninstall" ) uninstallFunc;; "enable" ) piholeEnable 1;; - "disable" ) piholeEnable 0 $2;; + "disable" ) piholeEnable 0 "$2";; "status" ) piholeStatus "$2";; "restartdns" ) restartDNS;; "-a" | "admin" ) webpageFunc "$@";; "-t" | "tail" ) tailFunc;; "checkout" ) piholeCheckoutFunc "$@";; + "tricorder" ) tricorderFunc;; * ) helpFunc;; esac diff --git a/test/test_automated_install.py b/test/test_automated_install.py index 8e36fc96..60772625 100644 --- a/test/test_automated_install.py +++ b/test/test_automated_install.py @@ -402,6 +402,61 @@ def test_FTL_binary_installed_and_responsive_no_errors(Pihole): # assert '644 /run/pihole-FTL.pid' in support_files.stdout # assert '644 /var/log/pihole-FTL.log' in support_files.stdout +def test_IPv6_only_link_local(Pihole): + ''' confirms IPv6 blocking is disabled for Link-local address ''' + # mock ip -6 address to return Link-local address + mock_command_2('ip', {'-6 address':('inet6 fe80::d210:52fa:fe00:7ad7/64 scope link', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found neither IPv6 ULA nor GUA address, blocking IPv6 ads will not be enabled' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_only_ULA(Pihole): + ''' confirms IPv6 blocking is enabled for ULA addresses ''' + # mock ip -6 address to return ULA address + mock_command_2('ip', {'-6 address':('inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_only_GUA(Pihole): + ''' confirms IPv6 blocking is enabled for GUA addresses ''' + # mock ip -6 address to return GUA address + mock_command_2('ip', {'-6 address':('inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 GUA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_GUA_ULA_test(Pihole): + ''' confirms IPv6 blocking is enabled for GUA and ULA addresses ''' + # mock ip -6 address to return GUA and ULA addresses + mock_command_2('ip', {'-6 address':('inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global\ninet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_ULA_GUA_test(Pihole): + ''' confirms IPv6 blocking is enabled for GUA and ULA addresses ''' + # mock ip -6 address to return ULA and GUA addresses + mock_command_2('ip', {'-6 address':('inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global\ninet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + # Helper functions def mock_command(script, args, container): ''' Allows for setup of commands we don't really want to have to run for real in unit tests ''' @@ -424,6 +479,27 @@ def mock_command(script, args, container): chmod +x {script} rm -f /var/log/{scriptlog}'''.format(script=full_script_path, content=mock_script, scriptlog=script)) +def mock_command_2(script, args, container): + ''' Allows for setup of commands we don't really want to have to run for real in unit tests ''' + full_script_path = '/usr/local/bin/{}'.format(script) + mock_script = dedent('''\ + #!/bin/bash -e + echo "\$0 \$@" >> /var/log/{script} + case "\$1 \$2" in'''.format(script=script)) + for k, v in args.iteritems(): + case = dedent(''' + \"{arg}\") + echo \"{res}\" + exit {retcode} + ;;'''.format(arg=k, res=v[0], retcode=v[1])) + mock_script += case + mock_script += dedent(''' + esac''') + container.run(''' + cat < {script}\n{content}\nEOF + chmod +x {script} + rm -f /var/log/{scriptlog}'''.format(script=full_script_path, content=mock_script, scriptlog=script)) + def run_script(Pihole, script): result = Pihole.run(script) assert result.rc == 0 From 536585b8460defd5de88cec786808e26c410408e Mon Sep 17 00:00:00 2001 From: Adam Warner Date: Wed, 21 Jun 2017 12:49:05 +0100 Subject: [PATCH 095/162] Colourise Core Output Text (#1471) * Define colours within COL_TABLE * Do not output colours for non-terminal instances * Removed ":::" * Fixed indenting & spacing * Made output consistent throughout project * Reworded text to fit on standard 80 char wide Terminal screen * Made 'sudo raspi-config' warning (insufficient disk space) only show on RPi * Make "Installation/Update Complete" the final msg * Remove redundant messages * Simplify update available message * Confirm user would like to begin uninstall * If "git pull" string says "Already up-to-date.", place [i] before it * Colour Temp/Interface output * Made `pihole disable 5z` invalid * Added error fallback if invalid argument (not s/m) is detected * Quoted "$2" for consistency * Updated help text * L185/286: Replaced echo with redirect * User agents for adblock.mahakala.is/adaway.org unnecessary * Print newline on confirmation of repository reset * Add output to admin-related dnsmasq restarts * Return error message for "pihole -q" * Imply default checkout behaviour with y/N * Fix uninstall failing to remove pihole user * Print checkout 'git remote show origin' STDERR on new line * Replaced checkout "AdminLTE" wording with "Web Admin" --- advanced/Scripts/COL_TABLE | 28 ++ advanced/Scripts/list.sh | 112 +++--- advanced/Scripts/piholeCheckout.sh | 135 ++++--- advanced/Scripts/piholeLogFlush.sh | 7 +- advanced/Scripts/update.sh | 92 ++--- advanced/Scripts/webpage.sh | 37 +- automated install/basic-install.sh | 537 +++++++++++++++------------ automated install/uninstall.sh | 138 ++++--- gravity.sh | 565 +++++++++++++++-------------- pihole | 107 ++++-- test/test_automated_install.py | 110 ++++-- 11 files changed, 1076 insertions(+), 792 deletions(-) create mode 100644 advanced/Scripts/COL_TABLE diff --git a/advanced/Scripts/COL_TABLE b/advanced/Scripts/COL_TABLE new file mode 100644 index 00000000..20dd98b0 --- /dev/null +++ b/advanced/Scripts/COL_TABLE @@ -0,0 +1,28 @@ +if [[ -t 1 ]] && [[ $(tput colors) -ge 8 ]]; then + COL_NC='' + COL_WHITE='' + COL_BLACK='' + COL_BLUE='' + COL_LIGHT_BLUE='' + COL_GREEN='' + COL_LIGHT_GREEN='' + COL_CYAN='' + COL_LIGHT_CYAN='' + COL_RED='' + COL_LIGHT_RED='' + COL_URG_RED='' + COL_PURPLE='' + COL_LIGHT_PURPLE='' + COL_BROWN='' + COL_YELLOW='' + COL_GRAY='' + COL_LIGHT_GRAY='' + COL_DARK_GRAY='' +fi + +TICK="[${COL_LIGHT_GREEN}✓${COL_NC}]" +CROSS="[${COL_LIGHT_RED}✗${COL_NC}]" +INFO="[i]" +QST="[?]" +DONE="${COL_LIGHT_GREEN} done!${COL_NC}" +OVER="\r\033[K" diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh index 308e1f5e..9d587296 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -24,6 +24,10 @@ domToRemoveList=() listMain="" listAlt="" +colfile="/opt/pihole/COL_TABLE" +source ${colfile} + + helpFunc() { if [[ "${listMain}" == "${whitelist}" ]]; then param="w" @@ -64,8 +68,9 @@ HandleOther() { # Check validity of domain validDomain=$(echo "${domain}" | perl -lne 'print if /(?!.*[^a-z0-9-\.].*)^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9-]+\.)*[a-z]{2,63}/') if [[ -z "${validDomain}" ]]; then - echo "::: $1 is not a valid argument or domain name" + echo -e " ${CROSS} $1 is not a valid argument or domain name!" else + echo -e " ${TICK} $1 is a valid domain name!" domList=("${domList[@]}" ${validDomain}) fi } @@ -93,6 +98,10 @@ PoplistFile() { AddDomain() { list="$2" domain=$(EscapeRegexp "$1") + + [[ "${list}" == "${whitelist}" ]] && listname="whitelist" + [[ "${list}" == "${blacklist}" ]] && listname="blacklist" + [[ "${list}" == "${wildcardlist}" ]] && listname="wildcard blacklist" if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then bool=true @@ -102,14 +111,14 @@ AddDomain() { if [[ "${bool}" == false ]]; then # Domain not found in the whitelist file, add it! if [[ "${verbose}" == true ]]; then - echo "::: Adding $1 to $list..." + echo -e " ${INFO} Adding $1 to $listname..." fi reload=true # Add it to the list we want to add it to echo "$1" >> "${list}" else if [[ "${verbose}" == true ]]; then - echo "::: ${1} already exists in ${list}, no need to add!" + echo -e " ${INFO} ${1} already exists in ${listname}, no need to add!" fi fi elif [[ "${list}" == "${wildcardlist}" ]]; then @@ -124,7 +133,7 @@ AddDomain() { if [[ "${bool}" == false ]]; then if [[ "${verbose}" == true ]]; then - echo "::: Adding $1 to wildcard blacklist..." + echo -e " ${INFO} Adding $1 to wildcard blacklist..." fi reload=true echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}" @@ -133,67 +142,78 @@ AddDomain() { fi else if [[ "${verbose}" == true ]]; then - echo "::: ${1} already exists in wildcard blacklist, no need to add!" + echo -e " ${INFO} ${1} already exists in wildcard blacklist, no need to add!" fi fi fi } RemoveDomain() { - list="$2" - domain=$(EscapeRegexp "$1") + list="$2" + domain=$(EscapeRegexp "$1") + + [[ "${list}" == "${whitelist}" ]] && listname="whitelist" + [[ "${list}" == "${blacklist}" ]] && listname="blacklist" + [[ "${list}" == "${wildcardlist}" ]] && listname="wildcard blacklist" - if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then - bool=true - # Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa - grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false - if [[ "${bool}" == true ]]; then - # Remove it from the other one - echo "::: Removing $1 from $list..." - # /I flag: search case-insensitive - sed -i "/${domain}/Id" "${list}" - reload=true - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} does not exist in ${list}, no need to remove!" - fi - fi - elif [[ "${list}" == "${wildcardlist}" ]]; then - bool=true - # Is it in the list? - grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false - if [[ "${bool}" == true ]]; then - # Remove it from the other one - echo "::: Removing $1 from $list..." - # /I flag: search case-insensitive - sed -i "/address=\/${domain}/Id" "${list}" - reload=true - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} does not exist in ${list}, no need to remove!" - fi + if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then + bool=true + # Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa + grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false + if [[ "${bool}" == true ]]; then + # Remove it from the other one + echo -e " ${INFO} Removing $1 from $listname..." + # /I flag: search case-insensitive + sed -i "/${domain}/Id" "${list}" + reload=true + else + if [[ "${verbose}" == true ]]; then + echo -e " ${INFO} ${1} does not exist in ${listname}, no need to remove!" fi fi + elif [[ "${list}" == "${wildcardlist}" ]]; then + bool=true + # Is it in the list? + grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false + if [[ "${bool}" == true ]]; then + # Remove it from the other one + echo -e " ${INFO} Removing $1 from $listname..." + # /I flag: search case-insensitive + sed -i "/address=\/${domain}/Id" "${list}" + reload=true + else + if [[ "${verbose}" == true ]]; then + echo -e " ${INFO} ${1} does not exist in ${listname}, no need to remove!" + fi + fi + fi } Reload() { # Reload hosts file + echo "" + echo -e " ${INFO} Updating gravity..." + echo "" pihole -g -sd } Displaylist() { - if [[ "${listMain}" == "${whitelist}" ]]; then - string="gravity resistant domains" + if [[ -f ${listMain} ]]; then + if [[ "${listMain}" == "${whitelist}" ]]; then + string="gravity resistant domains" + else + string="domains caught in the sinkhole" + fi + verbose=false + echo -e "Displaying $string:\n" + count=1 + while IFS= read -r RD; do + echo " ${count}: ${RD}" + count=$((count+1)) + done < "${listMain}" else - string="domains caught in the sinkhole" + echo -e " ${COL_LIGHT_RED}${listMain} does not exist!${COL_NC}" 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; } diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh index e2c0ab11..102db2ba 100644 --- a/advanced/Scripts/piholeCheckout.sh +++ b/advanced/Scripts/piholeCheckout.sh @@ -9,7 +9,8 @@ # Please see LICENSE file for your rights under this license. readonly PI_HOLE_FILES_DIR="/etc/.pihole" -PH_TEST="true" source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" +PH_TEST="true" +source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" # webInterfaceGitUrl set in basic-install.sh # webInterfaceDir set in basic-install.sh @@ -20,9 +21,8 @@ PH_TEST="true" source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" source "${setupVars}" update="false" -# Colour codes -red="\e[1;31m" -def="\e[0m" +coltable="/opt/pihole/COL_TABLE" +source ${coltable} fully_fetch_repo() { # Add upstream branches to shallow clone @@ -41,10 +41,12 @@ fully_fetch_repo() { get_available_branches() { # Return available branches local directory="${1}" + local output cd "${directory}" || return 1 - # Get reachable remote branches - git remote show origin | grep 'tracked' | sed 's/tracked//;s/ //g' + # Get reachable remote branches, but store STDERR as STDOUT variable + output=$( { git remote show origin | grep 'tracked' | sed 's/tracked//;s/ //g'; } 2>&1 ) + echo "$output" return } @@ -72,29 +74,36 @@ checkout_pull_branch() { cd "${directory}" || return 1 oldbranch="$(git symbolic-ref HEAD)" - + git checkout "${branch}" || return 1 - if [ "$(git diff "${oldbranch}" | grep -c "^")" -gt "0" ]; then + if [[ "$(git diff "${oldbranch}" | grep -c "^")" -gt "0" ]]; then update="true" fi - git pull || return 1 + git_pull=$(git pull || return 1) + + if [[ "$git_pull" == *"up-to-date"* ]]; then + echo -e "\n ${INFO} $(git pull)" + else + echo -e "$git_pull\n" + fi + return 0 } warning1() { echo " Please note that changing branches severely alters your Pi-hole subsystems" echo " Features that work on the master branch, may not on a development branch" - echo -e " ${red}This feature is NOT supported unless a Pi-hole developer explicitly asks!${def}" + echo -e " ${COL_LIGHT_RED}This feature is NOT supported unless a Pi-hole developer explicitly asks!${COL_NC}" read -r -p " Have you read and understood this? [y/N] " response case ${response} in [yY][eE][sS]|[yY]) - echo "::: Continuing with branch change." + echo "" return 0 ;; *) - echo "::: Branch change has been cancelled." + echo -e "\n ${INFO} Branch change has been cancelled" return 1 ;; esac @@ -107,24 +116,23 @@ checkout() { # Avoid globbing set -f - #This is unlikely + # This is unlikely if ! is_repo "${PI_HOLE_FILES_DIR}" ; then - echo "::: Critical Error: Core Pi-hole repo is missing from system!" - echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole" + echo -e " ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system! + Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}" exit 1; fi if [[ ${INSTALL_WEB} == "true" ]]; then if ! is_repo "${webInterfaceDir}" ; then - echo "::: Critical Error: Web Admin repo is missing from system!" - echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole" + echo -e " ${COL_LIGHT_RED}Error: Web Admin repo is missing from system! + Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}" exit 1; fi fi if [[ -z "${1}" ]]; then - echo "::: No option detected. Please use 'pihole checkout '." - echo "::: Or enter the repository and branch you would like to check out:" - echo "::: 'pihole checkout '" + echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC} + Try 'pihole checkout --help' for more information." exit 1 fi @@ -134,72 +142,91 @@ checkout() { if [[ "${1}" == "dev" ]] ; then # Shortcut to check out development branches - echo "::: Shortcut \"dev\" detected - checking out development / devel branches ..." - echo "::: Pi-hole core" - fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo "Unable to pull Core developement branch"; exit 1; } + echo -e " ${INFO} Shortcut \"dev\" detected - checking out development / devel branches..." + echo -e " ${INFO} Pi-hole core" + fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core developement branch"; exit 1; } if [[ ${INSTALL_WEB} == "true" ]]; then - echo "::: Web interface" - fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo "Unable to pull Web development branch"; exit 1; } + echo -e " ${INFO} Web interface" + fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; } fi - echo "::: done!" + echo -e " ${TICK} Pi-hole core" elif [[ "${1}" == "master" ]] ; then # Shortcut to check out master branches - echo "::: Shortcut \"master\" detected - checking out master branches ..." - echo "::: Pi-hole core" - fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "master" || { echo "Unable to pull Core master branch"; exit 1; } + echo -e " ${INFO} Shortcut \"master\" detected - checking out master branches..." + echo -e " ${INFO} Pi-hole core" + fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "master" || { echo " ${CROSS} Unable to pull Core master branch"; exit 1; } if [[ ${INSTALL_WEB} == "true" ]]; then - echo "::: Web interface" - fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo "Unable to pull web master branch"; exit 1; } + echo -e " ${INFO} Web interface" + fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; } fi - echo "::: done!" + echo -e " ${TICK} Web interface" + elif [[ "${1}" == "core" ]] ; then - echo -n "::: Fetching remote branches for Pi-hole core from ${piholeGitUrl} ... " + str="Fetching branches from ${piholeGitUrl}" + echo -ne " ${INFO} $str" if ! fully_fetch_repo "${PI_HOLE_FILES_DIR}" ; then - echo "::: Fetching all branches for Pi-hole core repo failed!" + echo -e " ${CROSS} $str" exit 1 fi corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}")) - echo " done!" - echo "::: ${#corebranches[@]} branches available" - echo ":::" - # Have to user chosing the branch he wants + + if [[ "${corebranches[@]}" == *"master"* ]]; then + echo -e "${OVER} ${TICK} $str + ${INFO} ${#corebranches[@]} branches available for Pi-hole Core" + else + # Print STDERR output from get_available_branches + echo -e "${OVER} ${CROSS} $str\n\n${corebranches[*]}" + exit 1 + fi + + echo "" + # Have the user choose the branch they want if ! (for e in "${corebranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then - echo "::: Requested branch \"${2}\" is not available!" - echo "::: Available branches for core are:" - for e in "${corebranches[@]}"; do echo "::: $e"; done + echo -e " ${INFO} Requested branch \"${2}\" is not available" + echo -e " ${INFO} Available branches for Core are:" + for e in "${corebranches[@]}"; do echo " - $e"; done exit 1 fi checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}" - elif [[ "${1}" == "web" && "${INSTALL_WEB}" == "true" ]] ; then - echo -n "::: Fetching remote branches for the web interface from ${webInterfaceGitUrl} ... " + elif [[ "${1}" == "web" ]] && [[ "${INSTALL_WEB}" == "true" ]] ; then + str="Fetching branches from ${webInterfaceGitUrl}" + echo -ne " ${INFO} $str" if ! fully_fetch_repo "${webInterfaceDir}" ; then - echo "::: Fetching all branches for Pi-hole web interface repo failed!" + echo -e " ${CROSS} $str" exit 1 fi webbranches=($(get_available_branches "${webInterfaceDir}")) - echo " done!" - echo "::: ${#webbranches[@]} branches available" - echo ":::" - # Have to user chosing the branch he wants + + if [[ "${corebranches[@]}" == *"master"* ]]; then + echo -e "${OVER} ${TICK} $str + ${INFO} ${#webbranches[@]} branches available for Web Admin" + else + # Print STDERR output from get_available_branches + echo -e "${OVER} ${CROSS} $str\n\n${corebranches[*]}" + exit 1 + fi + + echo "" + # Have the user choose the branch they want if ! (for e in "${webbranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then - echo "::: Requested branch \"${2}\" is not available!" - echo "::: Available branches for web are:" - for e in "${webbranches[@]}"; do echo "::: $e"; done + echo -e " ${INFO} Requested branch \"${2}\" is not available" + echo -e " ${INFO} Available branches for Web Admin are:" + for e in "${webbranches[@]}"; do echo " - $e"; done exit 1 fi checkout_pull_branch "${webInterfaceDir}" "${2}" else - echo "::: Requested option \"${1}\" is not available!" + echo -e " ${INFO} Requested option \"${1}\" is not available" exit 1 fi # Force updating everything if [[ ! "${1}" == "web" && "${update}" == "true" ]]; then - echo "::: Running installer to upgrade your installation" + echo -e " ${INFO} Running installer to upgrade your installation" if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then exit 0 else - echo "Unable to complete update, contact Pi-hole" + echo -e " ${COL_LIGHT_RED} Error: Unable to complete update, please contact support${COL_NC}" exit 1 fi fi diff --git a/advanced/Scripts/piholeLogFlush.sh b/advanced/Scripts/piholeLogFlush.sh index cc553b32..2187f3ac 100755 --- a/advanced/Scripts/piholeLogFlush.sh +++ b/advanced/Scripts/piholeLogFlush.sh @@ -8,8 +8,11 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. +colfile="/opt/pihole/COL_TABLE" +source ${colfile} + if [[ "$@" != *"quiet"* ]]; then - echo -n "::: Flushing /var/log/pihole.log ..." + echo -ne " ${INFO} Flushing /var/log/pihole.log ..." fi if [[ "$@" == *"once"* ]]; then # Nightly logrotation @@ -41,5 +44,5 @@ else fi if [[ "$@" != *"quiet"* ]]; then - echo "... done!" + echo -e "${OVER} ${TICK} Flushed /var/log/pihole.log" fi diff --git a/advanced/Scripts/update.sh b/advanced/Scripts/update.sh index 6aef183b..e8155f1a 100755 --- a/advanced/Scripts/update.sh +++ b/advanced/Scripts/update.sh @@ -22,6 +22,10 @@ readonly PI_HOLE_FILES_DIR="/etc/.pihole" PH_TEST=true source ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh +colfile="/opt/pihole/COL_TABLE" +source ${colfile} + + # is_repo() sourced from basic-install.sh # make_repo() sourced from basic-install.sh # update_repo() source from basic-install.sh @@ -49,14 +53,14 @@ GitCheckUpdateAvail() { REMOTE="$(git rev-parse @{upstream})" if [[ ${#LOCAL} == 0 ]]; then - echo "::: Error: Local revision could not be obtained, ask Pi-hole support." - echo "::: Additional debugging output:" + echo -e " ${COL_LIGHT_RED}Error: Local revision could not be obtained, ask Pi-hole support." + echo -e " Additional debugging output:${COL_NC}" git status exit fi if [[ ${#REMOTE} == 0 ]]; then - echo "::: Error: Remote revision could not be obtained, ask Pi-hole support." - echo "::: Additional debugging output:" + echo -e " ${COL_LIGHT_RED}Error: Remote revision could not be obtained, ask Pi-hole support." + echo -e " Additional debugging output:${COL_NC}" git status exit fi @@ -94,52 +98,52 @@ main() { #This is unlikely if ! is_repo "${PI_HOLE_FILES_DIR}" ; then - echo "::: Critical Error: Core Pi-hole repo is missing from system!" - echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole" + echo -e " ${COL_LIGHT_RED}Critical Error: Core Pi-hole repo is missing from system!" + echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}" exit 1; fi - echo "::: Checking for updates..." + echo -e " ${INFO} Checking for updates..." if GitCheckUpdateAvail "${PI_HOLE_FILES_DIR}" ; then core_update=true - echo "::: Pi-hole Core: update available" + echo -e " ${INFO} Pi-hole Core:\t${COL_YELLOW}update available${COL_NC}" else core_update=false - echo "::: Pi-hole Core: up to date" + echo -e " ${INFO} Pi-hole Core:\t${COL_LIGHT_GREEN}up to date${COL_NC}" fi if FTLcheckUpdate ; then FTL_update=true - echo "::: FTL: update available" + echo -e " ${INFO} FTL:\t\t${COL_YELLOW}update available${COL_NC}" else FTL_update=false - echo "::: FTL: up to date" + echo -e " ${INFO} FTL:\t\t${COL_LIGHT_GREEN}up to date${COL_NC}" fi - + # Logic: Don't update FTL when there is a core update available # since the core update will run the installer which will itself # re-install (i.e. update) FTL if ${FTL_update} && ! ${core_update}; then - echo ":::" - echo "::: FTL out of date" + echo "" + echo -e " ${INFO} FTL out of date" FTLdetect - echo ":::" + echo "" fi if [[ ${INSTALL_WEB} == true ]]; then if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then - echo "::: Critical Error: Web Admin repo is missing from system!" - echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole" + echo -e " ${COL_LIGHT_RED}Critical Error: Web Admin repo is missing from system!" + echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}" exit 1; fi if GitCheckUpdateAvail "${ADMIN_INTERFACE_DIR}" ; then web_update=true - echo "::: Web Interface: update available" + echo -e " ${INFO} Web Interface:\t${COL_YELLOW}update available${COL_NC}" else web_update=false - echo "::: Web Interface: up to date" + echo -e " ${INFO} Web Interface:\t${COL_LIGHT_GREEN}up to date${COL_NC}" fi # Logic @@ -154,64 +158,64 @@ main() { if ! ${core_update} && ! ${web_update} ; then if ! ${FTL_update} ; then - echo ":::" - echo "::: Everything is up to date!" + echo "" + echo -e " ${TICK} Everything is up to date!" exit 0 fi elif ! ${core_update} && ${web_update} ; then - echo ":::" - echo "::: Pi-hole Web Admin files out of date" + echo "" + echo -e " ${INFO} Pi-hole Web Admin files out of date" getGitFiles "${ADMIN_INTERFACE_DIR}" "${ADMIN_INTERFACE_GIT_URL}" elif ${core_update} && ! ${web_update} ; then - echo ":::" - echo "::: Pi-hole core files out of date" + echo "" + echo -e " ${INFO} Pi-hole core files out of date" getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}" - ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || echo "Unable to complete update, contact Pi-hole" && exit 1 + ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || echo -e " ${COL_LIGHT_RED}Unable to complete update, contact Pi-hole${COL_NC}" && exit 1 elif ${core_update} && ${web_update} ; then - echo ":::" - echo "::: Updating Pi-hole core and web admin files" + echo "" + echo -e " ${INFO} Updating Pi-hole core and web admin files" getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}" - ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --unattended || echo "Unable to complete update, contact Pi-hole" && exit 1 + ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --unattended || echo -e " ${COL_LIGHT_RED}Unable to complete update, contact Pi-hole${COL_NC}" && exit 1 else - echo "*** Update script has malfunctioned, fallthrough reached. Please contact support" + echo -e " ${COL_LIGHT_RED}Update script has malfunctioned, fallthrough reached. Please contact support${COL_NC}" exit 1 fi else # Web Admin not installed, so only verify if core is up to date if ! ${core_update}; then if ! ${FTL_update} ; then - echo ":::" - echo "::: Everything is up to date!" + echo "" + echo -e " ${INFO} Everything is up to date!" exit 0 fi else - echo ":::" - echo "::: Pi-hole core files out of date" + echo "" + echo -e " ${INFO} Pi-hole core files out of date" getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}" - ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || echo "Unable to complete update, contact Pi-hole" && exit 1 + ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || echo -e " ${COL_LIGHT_RED}Unable to complete update, contact Pi-hole${COL_NC}" && exit 1 fi fi if [[ "${web_update}" == true ]]; then web_version_current="$(/usr/local/bin/pihole version --admin --current)" - echo ":::" - echo "::: Web Admin version is now at ${web_version_current/* v/v}}" - echo "::: If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'" + echo "" + echo -e " ${INFO} Web Admin version is now at ${web_version_current/* v/v}" + echo -e " ${INFO} If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'" fi if [[ "${core_update}" == true ]]; then pihole_version_current="$(/usr/local/bin/pihole version --pihole --current)" - echo ":::" - echo "::: Pi-hole version is now at ${pihole_version_current/* v/v}}" - echo "::: If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'" + echo "" + echo -e " ${INFO} Pi-hole version is now at ${pihole_version_current/* v/v}" + echo -e " ${INFO} If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'" fi if [[ ${FTL_update} == true ]]; then - FTL_version_current="$(/usr/local/bin/pihole version --ftl --current)" - echo ":::" - echo "::: FTL version is now at ${FTL_version_current/* v/v}}" + FTL_version_current="$(/usr/bin/pihole-FTL tag)" + echo "" + echo -e " ${INFO} FTL version is now at ${FTL_version_current/* v/v}" start_service pihole-FTL enable_service pihole-FTL fi diff --git a/advanced/Scripts/webpage.sh b/advanced/Scripts/webpage.sh index 8419aa8d..b05cdbfb 100755 --- a/advanced/Scripts/webpage.sh +++ b/advanced/Scripts/webpage.sh @@ -14,13 +14,17 @@ readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf" # 03 -> wildcards readonly dhcpstaticconfig="/etc/dnsmasq.d/04-pihole-static-dhcp.conf" +coltable="/opt/pihole/COL_TABLE" +if [[ -f ${coltable} ]]; then + source ${coltable} +fi + helpFunc() { echo "Usage: pihole -a [options] Example: pihole -a -p password Set options for the Admin Console Options: - -f, flush Flush the Pi-hole log -p, password Set Admin Console password -c, celsius Set Celsius as preferred temperature unit -f, fahrenheit Set Fahrenheit as preferred temperature unit @@ -58,6 +62,7 @@ delete_dnsmasq_setting() { SetTemperatureUnit() { change_setting "TEMPERATUREUNIT" "${unit}" + echo -e " ${TICK} Set temperature unit to ${unit}" } HashPassword() { @@ -89,7 +94,7 @@ SetWebPassword() { if [ "${PASSWORD}" == "" ]; then change_setting "WEBPASSWORD" "" - echo "Password Removed" + echo -e " ${TICK} Password Removed" exit 0 fi @@ -101,9 +106,9 @@ SetWebPassword() { hash=$(HashPassword ${PASSWORD}) # Save hash to file change_setting "WEBPASSWORD" "${hash}" - echo "New password set" + echo -e " ${TICK} New password set" else - echo "Passwords don't match. Your password has not been changed" + echo -e " ${CROSS} Passwords don't match. Your password has not been changed" exit 1 fi } @@ -213,11 +218,19 @@ Reboot() { } RestartDNS() { - if [ -x "$(command -v systemctl)" ]; then - systemctl restart dnsmasq &> /dev/null - else - service dnsmasq restart &> /dev/null - fi + local str="Restarting dnsmasq" + echo -ne " ${INFO} ${str}..." + if [[ -x "$(command -v systemctl)" ]]; then + systemctl restart dnsmasq + else + service dnsmasq restart + fi + + if [[ "$?" == 0 ]]; then + echo -e "${OVER} ${TICK} ${str}" + else + echo -e "${OVER} ${CROSS} ${str}" + fi } SetQueryLogOptions() { @@ -404,13 +417,13 @@ Interfaces: fi if [[ "${args[2]}" == "all" ]]; then - echo "Listening on all interfaces, permiting all origins, hope you have a firewall!" + echo -e " ${INFO} Listening on all interfaces, permiting all origins. Please use a firewall!" change_setting "DNSMASQ_LISTENING" "all" elif [[ "${args[2]}" == "local" ]]; then - echo "Listening on all interfaces, permitting only origins that are at most one hop away (local devices)" + echo -e " ${INFO} Listening on all interfaces, permiting origins from one hop away (LAN)" change_setting "DNSMASQ_LISTENING" "local" else - echo "Listening only on interface ${PIHOLE_INTERFACE}" + echo -e " ${INFO} Listening only on interface ${PIHOLE_INTERFACE}" change_setting "DNSMASQ_LISTENING" "single" fi diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index 053e04ba..10ad7aff 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -22,6 +22,7 @@ tmpLog=/tmp/pihole-install.log instalLogLoc=/etc/pihole/install.log setupVars=/etc/pihole/setupVars.conf lighttpdConfig=/etc/lighttpd/lighttpd.conf +coltable=/opt/pihole/COL_TABLE webInterfaceGitUrl="https://github.com/pi-hole/AdminLTE.git" webInterfaceDir="/var/www/html/admin" @@ -54,15 +55,29 @@ skipSpaceCheck=false reconfigure=false runUnattended=false +if [[ -f ${coltable} ]]; then + source ${coltable} +else + COL_NC='\e[0m' # No Color + COL_LIGHT_GREEN='\e[1;32m' + COL_LIGHT_RED='\e[1;31m' + TICK="[${COL_LIGHT_GREEN}✓${COL_NC}]" + CROSS="[${COL_LIGHT_RED}✗${COL_NC}]" + INFO="[i]" + DONE="${COL_LIGHT_GREEN} done!${COL_NC}" + OVER="\r\033[K" +fi + + show_ascii_berry() { - echo " - .;;,. + echo -e " + ${COL_LIGHT_GREEN}.;;,. .ccccc:,. :cccclll:. ..,, :ccccclll. ;ooodc 'ccll:;ll .oooodc .;cll.;;looo:. - .. ','. + ${COL_LIGHT_RED}.. ','. .',,,,,,'. .',,,,,,,,,,. .',,,,,,,,,,,,.... @@ -75,7 +90,7 @@ show_ascii_berry() { ....',,,,,,,,,,,,. .',,,,,,,,,'. .',,,,,,'. - ..'''. + ..'''.${COL_NC} " } @@ -148,7 +163,7 @@ elif command -v rpm &> /dev/null; then DNSMASQ_USER="nobody" else - echo "OS distribution not supported" + echo -e " ${CROSS} OS distribution not supported" exit fi } @@ -176,14 +191,14 @@ is_repo() { make_repo() { local directory="${1}" local remoteRepo="${2}" - - echo -n "::: Cloning ${remoteRepo} into ${directory}..." + str="Clone ${remoteRepo} into ${directory}" + echo -ne " ${INFO} ${str}..." # Clean out the directory if it exists for git to clone into if [[ -d "${directory}" ]]; then rm -rf "${directory}" fi git clone -q --depth 1 "${remoteRepo}" "${directory}" &> /dev/null || return $? - echo " done!" + echo -e "${OVER} ${TICK} ${str}" return 0 } @@ -191,14 +206,15 @@ update_repo() { local directory="${1}" local curdir + local str="Update repo in ${1}" curdir="${PWD}" cd "${directory}" &> /dev/null || return 1 # Pull the latest commits - echo -n "::: Updating repo in ${1}..." + echo -ne " ${INFO} ${str}..." git stash --all --quiet &> /dev/null || true # Okay for stash failure git clean --force -d || true # Okay for already clean directory git pull --quiet &> /dev/null || return $? - echo " done!" + echo -e "${OVER} ${TICK} ${str}" cd "${curdir}" &> /dev/null || return 1 return 0 } @@ -208,15 +224,16 @@ getGitFiles() { # as arguments 1 and 2 local directory="${1}" local remoteRepo="${2}" - echo ":::" - echo "::: Checking for existing repository..." + local str="Check for existing repository in ${1}" + echo -ne " ${INFO} ${str}..." if is_repo "${directory}"; then - update_repo "${directory}" || { echo "*** Error: Could not update local repository. Contact support."; exit 1; } - echo " done!" + echo -e "${OVER} ${TICK} ${str}" + update_repo "${directory}" || { echo -e "\n ${COL_LIGHT_RED}Error: Could not update local repository. Contact support.${COL_NC}"; exit 1; } else - make_repo "${directory}" "${remoteRepo}" || { echo "Unable to clone repository, please contact support"; exit 1; } - echo " done!" + echo -e "${OVER} ${CROSS} ${str}" + make_repo "${directory}" "${remoteRepo}" || { echo -e "\n ${COL_LIGHT_RED}Error: Could not update local repository. Contact support.${COL_NC}"; exit 1; } fi + echo "" return 0 } @@ -224,9 +241,10 @@ resetRepo() { local directory="${1}" cd "${directory}" &> /dev/null || return 1 - echo -n "::: Resetting repo in ${1}..." + str="Resetting repository within ${1}..." + echo -ne " ${INFO} ${str}" git reset --hard &> /dev/null || return $? - echo " done!" + echo -e "${OVER} ${TICK} ${str}" return 0 } @@ -263,29 +281,35 @@ verifyFreeDiskSpace() { # 50MB is the minimum space needed (45MB install (includes web admin bootstrap/jquery libraries etc) + 5MB one day of logs.) # - Fourdee: Local ensures the variable is only created, and accessible within this function/void. Generally considered a "good" coding practice for non-global variables. - echo "::: Verifying free disk space..." + local str="Disk space check" local required_free_kilobytes=51200 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" + echo -e " ${CROSS} ${str} + Unknown free disk space! + We were unable to determine available free disk space on this system. + You may override this check, however, it is not recommended + The option '${COL_LIGHT_RED}--i_do_not_follow_recommendations${COL_NC}' can override this + e.g: curl -L https://install.pi-hole.net | bash /dev/stdin ${COL_LIGHT_RED}