From 6fa00e7cc86a8fb661ab3343c67b2d30e5d583f1 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 20 May 2017 01:34:13 -0500 Subject: [PATCH 01/75] 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 02/75] 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 69fe889f92904ed73a02f75f01be80111cf9fe67 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sun, 21 May 2017 23:25:53 -0500 Subject: [PATCH 03/75] 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 04/75] 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 05/75] 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 06/75] 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 07/75] 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 08/75] 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 09/75] 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 10/75] 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 085f2c6ca0f1f19649a523f14df6327b71adbb48 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Tue, 23 May 2017 22:32:30 -0500 Subject: [PATCH 11/75] 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 12/75] 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 76266cf31b1b631a6646add520e6b712b76f2acd Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Wed, 24 May 2017 15:29:31 -0500 Subject: [PATCH 13/75] 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 14/75] 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 15/75] 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 16/75] 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 17/75] 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 18/75] 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 19/75] 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 96f01e670fa13f0d5c77a7d305285d3b750d1668 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Fri, 26 May 2017 12:16:22 -0500 Subject: [PATCH 20/75] 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 21/75] 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 22/75] 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 23/75] 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 24/75] 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 d51e0c49b1009c2637d52deecd71a4314c32b2a4 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 27 May 2017 13:44:33 -0500 Subject: [PATCH 25/75] 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 2fea5d428d95030ad22393e9f8fc1d9653136375 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 27 May 2017 15:47:15 -0500 Subject: [PATCH 26/75] 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 27/75] 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 b207fadc04f16422d00a9b0bf9c03567f1ef5fcd Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Thu, 1 Jun 2017 00:18:06 -0500 Subject: [PATCH 28/75] 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 29/75] 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 30/75] 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 92b5fe4be45552aff30f7acbbe78bca9ec0e67cd Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 5 Jun 2017 14:55:58 -0500 Subject: [PATCH 31/75] 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 32/75] 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 33/75] 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 34/75] 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 35/75] 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 36/75] 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 37/75] 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 38/75] 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 39/75] 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 40/75] 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 41/75] 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 42/75] 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 5f00347019d2341cfa1a3f9e130b4ce92ae8acb9 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 26 Jun 2017 21:34:39 -0500 Subject: [PATCH 43/75] appease shellcheck by removing two unneccesary functions and making some if/else blocks --- advanced/Scripts/piholeDebug.sh | 44 +++++++++------------------------ 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index d6526d9c..59029eb0 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -131,6 +131,7 @@ ${WEB_GIT_DIRECTORY} ${BLOCK_PAGE_DIRECTORY}) # Store the required directories in an array so it can be parsed through +mapfile -t array <<< "$var" REQUIRED_FILES=(${PIHOLE_CRON_FILE} ${PIHOLE_DNS_CONFIG_FILE} ${PIHOLE_DHCP_CONFIG_FILE} @@ -190,20 +191,6 @@ copy_to_debug_log() { cat /proc/$$/fd/3 >> "${PIHOLE_DEBUG_LOG}" } -echo_succes_or_fail() { - # 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}" - else - local message="${1}" - # Otherwise, show a error - log_write "${CROSS} ${message}" - fi -} - initiate_debug() { # Clear the screen so the debug log is readable clear @@ -235,19 +222,6 @@ 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 -} - compare_local_version_to_git_version() { # The git directory to check local git_dir="${1}" @@ -266,18 +240,21 @@ compare_local_version_to_git_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 "${git_dir}" && \ + if [[ -d "${git_dir}" ]]; then # move into it 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 - local remote_version=$(git describe --tags --abbrev=0); + local remote_version + remote_version=$(git describe --tags --abbrev=0); # What branch they are on - local remote_branch=$(git rev-parse --abbrev-ref HEAD); + local remote_branch + remote_branch=$(git rev-parse --abbrev-ref HEAD); # The commit they are on - local remote_commit=$(git describe --long --dirty --tags --always) + local remote_commit + 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 [[ "${remote_version}" == "$(pihole -v | awk '/${search_term}/ {print $6}' | cut -d ')' -f1)" ]]; then @@ -307,6 +284,9 @@ compare_local_version_to_git_version() { # and exit with a non zero code return 1 fi + else + : + fi } check_ftl_version() { @@ -874,7 +854,7 @@ dir_check() { # do nothing : || \ # Otherwise, show an error - echo_succes_or_fail "${COL_LIGHT_RED}${directory} does not exist.${COL_NC}" + log_write "${COL_LIGHT_RED}${directory} does not exist.${COL_NC}" done } From b6a2a4ad5a8c67c9f214aa38e69337036417bd23 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 26 Jun 2017 21:51:41 -0500 Subject: [PATCH 44/75] more shellcheck fixes --- advanced/Scripts/piholeDebug.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 59029eb0..2b45eb72 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -372,7 +372,7 @@ get_distro_attributes() { 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) )' + IFS=$'\r\n' command eval "distro_info=( $(cat /etc/*release) )" # Set a named variable for better readability local distro_attribute @@ -402,11 +402,13 @@ 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 && \ + if [[ -r /etc/*release ]]; then # display the attributes to the user from the function made earlier - get_distro_attributes || \ + get_distro_attributes + else # 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} (${FAQ_HARDWARE_REQUIREMENTS})" + fi } processor_check() { @@ -440,11 +442,13 @@ processor_check() { parse_setup_vars() { echo_current_diagnostic "Setup variables" # If the file exists, - if_file_exists "${PIHOLE_SETUP_VARS_FILE}" && \ + if [[ -r "${PIHOLE_SETUP_VARS_FILE}" ]]; then # parse it - parse_file "${PIHOLE_SETUP_VARS_FILE}" || \ + parse_file "${PIHOLE_SETUP_VARS_FILE}" + else # If not, show an error log_write "${CROSS} ${COL_LIGHT_RED}Could not read ${PIHOLE_SETUP_VARS_FILE}.${COL_NC}" + fi } does_ip_match_setup_vars() { @@ -453,7 +457,7 @@ 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 ${PIHOLE_SETUP_VARS_FILE} | grep IPV${protocol}_ADDRESS | cut -d '=' -f2) + local setup_vars_ip=$(< ${PIHOLE_SETUP_VARS_FILE} | grep IPV${protocol}_ADDRESS | cut -d '=' -f2) # If it's an IPv6 address if [[ "${protocol}" == "6" ]]; then # Strip off the / (CIDR notation) From 22fac5e1e0bfed3a0df3964969e3b7f4ed889c0d Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 26 Jun 2017 22:03:45 -0500 Subject: [PATCH 45/75] additional shellcheck fixes --- advanced/Scripts/piholeDebug.sh | 64 ++++++++++++++++----------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 2b45eb72..cdeea52c 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -162,12 +162,14 @@ source_setup_variables() { # Display the current test that is running log_write "\n${COL_LIGHT_PURPLE}*** [ INITIALIZING ]${COL_NC} Sourcing setup variables" # If the variable file exists, - if_file_exists "${PIHOLE_SETUP_VARS_FILE}" && \ + if ls "${PIHOLE_SETUP_VARS_FILE}" 1> /dev/null 2>&1; then log_write "${INFO} Sourcing ${PIHOLE_SETUP_VARS_FILE}..."; # source it - source ${PIHOLE_SETUP_VARS_FILE} || \ + source ${PIHOLE_SETUP_VARS_FILE} + else # If it can't, show an error log_write "${PIHOLE_SETUP_VARS_FILE} ${COL_LIGHT_RED}does not exist or cannot be read.${COL_NC}" + fi } make_temporary_log() { @@ -209,19 +211,6 @@ echo_current_diagnostic() { log_write "\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 - # Return success - return 0 - else - # Otherwise, return a failure - return 1 - fi -} - compare_local_version_to_git_version() { # The git directory to check local git_dir="${1}" @@ -372,7 +361,7 @@ get_distro_attributes() { 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) )" + IFS=$'\r\n' command eval 'distro_info=( $(cat /etc/*release) )' # Set a named variable for better readability local distro_attribute @@ -402,7 +391,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 [[ -r /etc/*release ]]; then + if ls /etc/*release 1> /dev/null 2>&1; then # display the attributes to the user from the function made earlier get_distro_attributes else @@ -457,7 +446,7 @@ 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=$(< ${PIHOLE_SETUP_VARS_FILE} | 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 / (CIDR notation) @@ -613,10 +602,12 @@ check_required_ports() { 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 + 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}') + local port_number + port_number="$(echo "${ports_in_use[$i]}" | awk '{print $1}')" + local service_name + 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) compare_port_to_service_assigned "${resolver}" @@ -647,14 +638,18 @@ check_x_headers() { # 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') + local block_page + 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') + local dashboard + 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!" + local block_page_working + block_page_working="X-Pi-hole: A black hole for Internet advertisements." + local dashboard_working + 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 + if [[ $block_page == "$block_page_working" ]]; then # display a success message log_write "$TICK ${COL_LIGHT_GREEN}${block_page}${COL_NC}" else @@ -663,7 +658,7 @@ check_x_headers() { 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 + if [[ $dashboard == "$dashboard_working" ]]; then # then we can show a success log_write "$TICK ${COL_LIGHT_GREEN}${dashboard}${COL_NC}" else @@ -682,7 +677,6 @@ dig_at() { 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 local remote_dig @@ -852,13 +846,15 @@ dir_check() { # Display the current test that is running echo_current_diagnostic "contents of ${COL_CYAN}${directory}${COL_NC}" # For each file in the directory, - for filename in "${directory}"; do + for filename in ${directory}; do # check if exists first; if it does, - if_file_exists "${filename}" && \ - # do nothing - : || \ - # Otherwise, show an error - log_write "${COL_LIGHT_RED}${directory} does not exist.${COL_NC}" + if ls "${filename}" 1> /dev/null 2>&1; then + # do nothing + : + else + # Otherwise, show an error + log_write "${COL_LIGHT_RED}${directory} does not exist.${COL_NC}" + fi done } From ab1a6d8829b2d9d86f1bc48dd2fd034dba28736d Mon Sep 17 00:00:00 2001 From: Adam Warner Date: Thu, 29 Jun 2017 02:18:52 +0100 Subject: [PATCH 46/75] Fix install script using IPv6 CIDR notation (#1570) --- automated install/basic-install.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index 0878dc30..ee6a1d56 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -368,8 +368,8 @@ useIPv6dialog() { # 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" + [[ "${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 @@ -1495,7 +1495,7 @@ main() { welcomeDialogs # Create directory for Pi-hole storage mkdir -p /etc/pihole/ - + stop_service dnsmasq if [[ ${INSTALL_WEB} == true ]]; then stop_service lighttpd @@ -1575,7 +1575,7 @@ main() { if [[ "${useUpdateVars}" == false ]]; then displayFinalMessage "${pw}" fi - + if [[ ${INSTALL_WEB} == true ]]; then if (( ${#pw} > 0 )) ; then echo -e " ${INFO} Web Interface password: ${COL_LIGHT_GREEN}${pw}${COL_NC} @@ -1597,7 +1597,7 @@ main() { else INSTALL_TYPE="Update" fi - + echo -e "\n ${INFO} The install log is located at: /etc/pihole/install.log ${COL_LIGHT_GREEN}${INSTALL_TYPE} Complete! ${COL_NC}" } From 04cef25addfbb4a43299ffe775e4b4f5b9559a0a Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Thu, 29 Jun 2017 11:17:19 -0500 Subject: [PATCH 47/75] remove color character codes before uploading so the log is more readable on our plaintext tricorder server --- advanced/Scripts/piholeDebug.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index cdeea52c..49c4cd5c 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -103,6 +103,7 @@ 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_DEBUG_LOG_SANITIZED="${LOG_DIRECTORY}/pihole_debug-sanitized.log" PIHOLE_FTL_LOG="${LOG_DIRECTORY}/pihole-FTL.log" PIHOLE_WEB_SERVER_ACCESS_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/access.log" @@ -190,7 +191,8 @@ 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 >> "${PIHOLE_DEBUG_LOG}" + cat /proc/$$/fd/3 > "${PIHOLE_DEBUG_LOG}" + sed 's/\[[0-9;]\{1,5\}m//g' > "${PIHOLE_DEBUG_LOG_SANITIZED}" <<< cat "${PIHOLE_DEBUG_LOG}" } initiate_debug() { @@ -976,13 +978,13 @@ 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 ${PIHOLE_DEBUG_LOG} | openssl s_client -quiet -connect tricorder.pi-hole.net:${TRICORDER_SSL_PORT_NUMBER} 2> /dev/null) + tricorder_token=$(cat ${PIHOLE_DEBUG_LOG_SANITIZED} | 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." # 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}) + tricorder_token=$(cat ${PIHOLE_DEBUG_LOG_SANITIZED} | nc tricorder.pi-hole.net ${TRICORDER_NC_PORT_NUMBER}) fi } @@ -1054,7 +1056,7 @@ upload_to_tricorder() { 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" + log_write " * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG_SANITIZED}${COL_NC}\n" } # Run through all the functions we made From 1957b002bc12fed57526d0ff51ac7d0c7777cf49 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Thu, 29 Jun 2017 11:37:58 -0500 Subject: [PATCH 48/75] add comments about X-Headers and further explain the file descriptor cod. --- advanced/Scripts/piholeDebug.sh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 49c4cd5c..d42e3517 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -180,7 +180,8 @@ make_temporary_log() { # https://stackoverflow.com/questions/18460186/writing-outputs-to-log-file-and-console exec 3>"$TEMPLOG" # Delete templog, but allow for addressing via file handle - # This lets us write to the log without having a temporary file on the drive + # This lets us write to the log without having a temporary file on the drive, which + # is meant to be a security measure so there is not a lingering file on the drive during the debug process rm "$TEMPLOG" } @@ -190,8 +191,12 @@ log_write() { } copy_to_debug_log() { - # Copy the contents of file descriptor 3 into the debug log so it can be uploaded to tricorder + # Copy the contents of file descriptor 3 into the debug log cat /proc/$$/fd/3 > "${PIHOLE_DEBUG_LOG}" + # Since we use color codes such as '\e[1;33m', they should be removed before being + # uploaded to our server, since it can't properly display in color + # This is accomplished by use sed to remove characters matching that patter + # The entire file is then copied over to a sanitized version of the log sed 's/\[[0-9;]\{1,5\}m//g' > "${PIHOLE_DEBUG_LOG_SANITIZED}" <<< cat "${PIHOLE_DEBUG_LOG}" } @@ -637,6 +642,10 @@ check_networking() { check_x_headers() { # The X-Headers allow us to determine from the command line if the Web + # lighttpd.conf has a directive to show "X-Pi-hole: A black hole for Internet advertisements." + # in the header of any Pi-holed domain + # Similarly, it will show "X-Pi-hole: The Pi-hole Web interface is working!" if you view the header returned + # when accessing the dashboard (i.e curl -I pi.hole/admin/) # 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 @@ -1061,9 +1070,9 @@ upload_to_tricorder() { # Run through all the functions we made make_temporary_log +initiate_debug # 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 From 05a724afaeb0bfd59829d5b5603c2acba4ea6fc4 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Thu, 29 Jun 2017 11:49:28 -0500 Subject: [PATCH 49/75] codacy appeasement: remove useless cats --- advanced/Scripts/piholeDebug.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index d42e3517..f98d986a 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -987,13 +987,13 @@ 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 ${PIHOLE_DEBUG_LOG_SANITIZED} | openssl s_client -quiet -connect tricorder.pi-hole.net:${TRICORDER_SSL_PORT_NUMBER} 2> /dev/null) + tricorder_token=$(< ${PIHOLE_DEBUG_LOG_SANITIZED} 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." # Save the token returned by our server in a variable - tricorder_token=$(cat ${PIHOLE_DEBUG_LOG_SANITIZED} | nc tricorder.pi-hole.net ${TRICORDER_NC_PORT_NUMBER}) + tricorder_token=$(< ${PIHOLE_DEBUG_LOG_SANITIZED} nc tricorder.pi-hole.net ${TRICORDER_NC_PORT_NUMBER}) fi } From ec4e9780ed0eb1dca0436d365b2b09b345117ab4 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Fri, 30 Jun 2017 14:52:33 +0200 Subject: [PATCH 50/75] Accept underscores when validating domain names (#1571) --- advanced/Scripts/list.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh index e7151cf6..86589083 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -62,11 +62,14 @@ EscapeRegexp() { } HandleOther() { - # First, convert everything to lowercase - domain=$(sed -e "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" <<< "$1") + # Convert to lowercase + domain="${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}/') + validDomain=$(perl -lne 'print if /^((-|_)*[a-z\d]((-|_)*[a-z\d])*(-|_)*)(\.(-|_)*([a-z\d]((-|_)*[a-z\d])*))*$/' <<< "${domain}") # Valid chars check + validDomain=$(perl -lne 'print if /^.{1,253}$/' <<< "${validDomain}") # Overall length check + validDomain=$(perl -lne 'print if /^[^\.]{1,63}(\.[^\.]{1,63})*$/' <<< "${validDomain}") # Length of each label + if [[ -z "${validDomain}" ]]; then echo -e " ${CROSS} $1 is not a valid argument or domain name!" else @@ -98,7 +101,7 @@ PoplistFile() { AddDomain() { list="$2" domain=$(EscapeRegexp "$1") - + [[ "${list}" == "${whitelist}" ]] && listname="whitelist" [[ "${list}" == "${blacklist}" ]] && listname="blacklist" [[ "${list}" == "${wildcardlist}" ]] && listname="wildcard blacklist" @@ -151,7 +154,7 @@ AddDomain() { RemoveDomain() { list="$2" domain=$(EscapeRegexp "$1") - + [[ "${list}" == "${whitelist}" ]] && listname="whitelist" [[ "${list}" == "${blacklist}" ]] && listname="blacklist" [[ "${list}" == "${wildcardlist}" ]] && listname="wildcard blacklist" From b3eb5c4f0e09506e30ce09b21c19c8c29bd21f4b Mon Sep 17 00:00:00 2001 From: Adam Warner Date: Sat, 1 Jul 2017 13:08:17 +0100 Subject: [PATCH 51/75] Colour Tweaks (#1549) --- advanced/Scripts/piholeCheckout.sh | 26 ++++++++++++++------------ advanced/Scripts/update.sh | 6 +----- automated install/basic-install.sh | 2 +- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh index 102db2ba..093c958e 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. # -# Switch Pi-hole subsystems to a different Github branch +# 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. @@ -60,7 +60,7 @@ fetch_checkout_pull_branch() { cd "${directory}" git remote set-branches origin "${branch}" || return 1 git stash --all --quiet &> /dev/null || true - git clean --force -d || true + git clean --quiet --force -d || true git fetch --quiet || return 1 checkout_pull_branch "${directory}" "${branch}" || return 1 } @@ -74,21 +74,21 @@ checkout_pull_branch() { cd "${directory}" || return 1 oldbranch="$(git symbolic-ref HEAD)" - - git checkout "${branch}" || return 1 + + git checkout "${branch}" --quiet || return 1 if [[ "$(git diff "${oldbranch}" | grep -c "^")" -gt "0" ]]; then update="true" fi git_pull=$(git pull || return 1) - + if [[ "$git_pull" == *"up-to-date"* ]]; then - echo -e "\n ${INFO} $(git pull)" + echo -e " ${INFO} $(git pull)" else echo -e "$git_pull\n" fi - + return 0 } @@ -143,13 +143,15 @@ checkout() { if [[ "${1}" == "dev" ]] ; then # Shortcut to check out development branches echo -e " ${INFO} Shortcut \"dev\" detected - checking out development / devel branches..." - echo -e " ${INFO} Pi-hole core" + echo "" + echo -e " ${INFO} Pi-hole Core" fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core developement branch"; exit 1; } if [[ ${INSTALL_WEB} == "true" ]]; then + echo "" echo -e " ${INFO} Web interface" fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; } fi - echo -e " ${TICK} Pi-hole core" + #echo -e " ${TICK} Pi-hole Core" elif [[ "${1}" == "master" ]] ; then # Shortcut to check out master branches echo -e " ${INFO} Shortcut \"master\" detected - checking out master branches..." @@ -159,8 +161,8 @@ checkout() { echo -e " ${INFO} Web interface" fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; } fi - echo -e " ${TICK} Web interface" - + #echo -e " ${TICK} Web Interface" + elif [[ "${1}" == "core" ]] ; then str="Fetching branches from ${piholeGitUrl}" echo -ne " ${INFO} $str" @@ -196,7 +198,7 @@ checkout() { exit 1 fi webbranches=($(get_available_branches "${webInterfaceDir}")) - + if [[ "${corebranches[@]}" == *"master"* ]]; then echo -e "${OVER} ${TICK} $str ${INFO} ${#webbranches[@]} branches available for Web Admin" diff --git a/advanced/Scripts/update.sh b/advanced/Scripts/update.sh index 779f6c8d..d4919d08 100755 --- a/advanced/Scripts/update.sh +++ b/advanced/Scripts/update.sh @@ -10,10 +10,7 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. - - # Variables - readonly ADMIN_INTERFACE_GIT_URL="https://github.com/pi-hole/AdminLTE.git" readonly ADMIN_INTERFACE_DIR="/var/www/html/admin" readonly PI_HOLE_GIT_URL="https://github.com/pi-hole/pi-hole.git" @@ -82,7 +79,6 @@ GitCheckUpdateAvail() { } FTLcheckUpdate() { - local FTLversion FTLversion=$(/usr/bin/pihole-FTL tag) local FTLlatesttag @@ -131,7 +127,7 @@ main() { # re-install (i.e. update) FTL if ${FTL_update} && ! ${core_update}; then echo "" - echo -e " ${INFO} FTL out of date" + echo -e " ${INFO} FTL out of date" FTLdetect echo "" fi diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index ee6a1d56..3c6b77af 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -212,7 +212,7 @@ update_repo() { # Pull the latest commits 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 clean --quiet --force -d || true # Okay for already clean directory git pull --quiet &> /dev/null || return $? echo -e "${OVER} ${TICK} ${str}" cd "${curdir}" &> /dev/null || return 1 From 6ce79ae1d0372a05fc129f39aa8b871ac8f8b314 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 1 Jul 2017 23:52:10 +0200 Subject: [PATCH 52/75] Fix git commands (#1577) --- advanced/Scripts/update.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/advanced/Scripts/update.sh b/advanced/Scripts/update.sh index d4919d08..71b7cecd 100755 --- a/advanced/Scripts/update.sh +++ b/advanced/Scripts/update.sh @@ -40,7 +40,7 @@ GitCheckUpdateAvail() { # @ alone is a shortcut for HEAD. Older versions of git # need @{0} - LOCAL="$("git rev-parse @{0}")" + LOCAL="$(git rev-parse "@{0}")" # The suffix @{upstream} to a branchname # (short form @{u}) refers @@ -49,7 +49,7 @@ GitCheckUpdateAvail() { # (configured with branch..remote and # branch..merge). A missing branchname # defaults to the current one. - REMOTE="$("git rev-parse @{upstream}")" + REMOTE="$(git rev-parse "@{upstream}")" if [[ ${#LOCAL} == 0 ]]; then echo -e " ${COL_LIGHT_RED}Error: Local revision could not be obtained, ask Pi-hole support." From 209fbf82c403c495867bae77b5ef585c1a76b986 Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Sun, 2 Jul 2017 23:21:00 +1000 Subject: [PATCH 53/75] Colourise tailFunc (#1550) * Colourise tailFunc * Strip month, day number and dnsmasq[PID] * Blocked domains show as light red * Queries show as standard colour * Everything else as dark gray * Change tailFunc highlighted lines * Highlight Blocked/Blacklist/Wildcard lines as red * Make DHCP lines default colour * Make sure tailFunc doesn't match on domain names --- pihole | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pihole b/pihole index 93b35393..3c321b93 100755 --- a/pihole +++ b/pihole @@ -340,8 +340,13 @@ piholeStatus() { } tailFunc() { + date=$(date +'%b %d ') echo -e " ${INFO} Press Ctrl-C to exit" - tail -F /var/log/pihole.log + tail -f /var/log/pihole.log | sed \ + -e "s,\(${date}\| dnsmasq\[.*[0-9]]\),,g" \ + -e "s,\(.*\(gravity.list\|black.list\| config \).* is \(${IPV4_ADDRESS%/*}\|${IPV6_ADDRESS:-NULL}\).*\),${COL_LIGHT_RED}&${COL_NC}," \ + -e "s,.*\(query\[A\|DHCP\).*,${COL_NC}&${COL_NC}," \ + -e "s,.*,${COL_DARK_GRAY}&${COL_NC}," exit 0 } From 1bebcef2658527a3159911fe824c0d92e759233d Mon Sep 17 00:00:00 2001 From: WaLLy3K Date: Tue, 4 Jul 2017 13:52:51 +1000 Subject: [PATCH 54/75] Make Chronometer usable on smaller screens (#1518) --- advanced/Scripts/chronometer.sh | 493 ++++++++++++++++++++------------ 1 file changed, 313 insertions(+), 180 deletions(-) diff --git a/advanced/Scripts/chronometer.sh b/advanced/Scripts/chronometer.sh index d9b7d05b..d9b01fc0 100755 --- a/advanced/Scripts/chronometer.sh +++ b/advanced/Scripts/chronometer.sh @@ -7,6 +7,7 @@ # # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. +LC_NUMERIC=C # Retrieve stats from FTL engine pihole-FTL() { @@ -32,43 +33,74 @@ pihole-FTL() { exec 3<&- fi else - echo -e "${COL_LIGHT_RED}FTL offline${COL_NC}" + echo "0" fi } -# Print spaces to align right-side content +# Print spaces to align right-side additional text 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") + local text_last - # Print string (Max 20 characters, prevents overflow) - printf "%s%s$spc" "$1" "${2:0:20}" + title="$1" + title_len="${#title}" + + text_main="$2" + text_main_nocol="$text_main" + if [[ "${text_main:0:1}" == "" ]]; then + text_main_nocol=$(sed 's/\[[0-9;]\{1,5\}m//g' <<< "$text_main") + fi + text_main_len="${#text_main_nocol}" + + text_addn="$3" + if [[ "$text_addn" == "last" ]]; then + text_addn="" + text_last="true" + fi + + # If there is additional text, define max length of text_main + if [[ -n "$text_addn" ]]; then + case "$scr_cols" in + [0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-4]) text_main_max_len="9";; + 4[5-9]) text_main_max_len="14";; + *) text_main_max_len="19";; + esac + fi + + [[ -z "$text_addn" ]] && text_main_max_len="$(( scr_cols - title_len ))" + + # Remove excess characters from main text + if [[ "$text_main_len" -gt "$text_main_max_len" ]]; then + # Trim text without colours + text_main_trim="${text_main_nocol:0:$text_main_max_len}" + # Replace with trimmed text + text_main="${text_main/$text_main_nocol/$text_main_trim}" + fi + + # Determine amount of spaces for each line + if [[ -n "$text_last" ]]; then + # Move cursor to end of screen + spc_num=$(( scr_cols - ( title_len + text_main_len ) )) + else + spc_num=$(( text_main_max_len - text_main_len )) + fi + + [[ "$spc_num" -le 0 ]] && spc_num="0" + spc=$(printf "%${spc_num}s") + #spc="${spc// /.}" # Debug: Visualise spaces + + printf "%s%s$spc" "$title" "$text_main" + + if [[ -n "$text_addn" ]]; then + printf "%s(%s)%s\n" "$COL_NC$COL_DARK_GRAY" "$text_addn" "$COL_NC" + else + # Do not print trailing newline on final line + [[ -z "$text_last" ]] && printf "%s\n" "$COL_NC" fi } # Perform on first Chrono run (not for JSON formatted string) get_init_stats() { - LC_NUMERIC=C - calcFunc(){ awk "BEGIN {print $*}"; } + calcFunc(){ awk "BEGIN {print $*}" 2> /dev/null; } # Convert bytes to human-readable format hrBytes() { @@ -90,33 +122,53 @@ get_init_stats() { # Convert seconds to human-readable format hrSecs() { - day=$(( $1/60/60/24 )); hrs=$(( $1/3600%24 )); mins=$(( ($1%3600)/60 )); secs=$(( $1%60 )) + 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='' + 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 + # Get RPi throttle state (RPi 3B only) & 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 + local sys_throttle_raw + local sys_rev_raw + + sys_throttle_raw=$(vgt=$(sudo vcgencmd get_throttled); echo "${vgt##*x}") + + # Active Throttle Notice: http://bit.ly/2gnunOo + if [[ "$sys_throttle_raw" != "0" ]]; then + case "$sys_throttle_raw" in + *0001) thr_type="${COL_YELLOW}Under Voltage";; + *0002) thr_type="${COL_LIGHT_BLUE}Arm Freq Cap";; + *0003) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC";; + *0004) thr_type="${COL_LIGHT_RED}Throttled";; + *0005) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";; + *0006) thr_type="${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";; + *0007) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";; + esac + [[ -n "$thr_type" ]] && sys_throttle="$thr_type${COL_DARK_GRAY}" + fi + + sys_rev_raw=$(awk '/Revision/ {print $3}' < /proc/cpuinfo) + case "$sys_rev_raw" in 000[2-6]) sys_model=" 1, Model B";; # 256MB - 000[7-9]) sys_model=" 1, Model A" ;; # 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 @@ -126,7 +178,7 @@ get_init_stats() { 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="" ;; + *) sys_model="";; esac sys_type="Raspberry Pi$sys_model" else @@ -137,7 +189,6 @@ get_init_stats() { # 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 @@ -168,80 +219,95 @@ get_sys_stats() { # Update every 12 refreshes (Def: every 60s) count=$((count+1)) if [[ "$count" == "1" ]] || (( "$count" % 12 == 0 )); then + # Do not source setupVars if file does not exist [[ -n "$setupVars" ]] && source "$setupVars" - - - ph_ver_raw=($(pihole -v -c 2> /dev/null | sed -n 's/^.* v/v/p')) + + mapfile -t 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}" + ph_core_ver="-1" 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 }')) + read -r -a 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 + + # Get DNS server count + dns_count="0" + [[ -n "${PIHOLE_DNS_1}" ]] && dns_count=$((dns_count+1)) + [[ -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+" fi - + + # Get screen size + read -r -a scr_size <<< "$(stty size 2>/dev/null || echo 24 80)" + scr_lines="${scr_size[0]}" + scr_cols="${scr_size[1]}" + + # Determine Chronometer size behaviour + if [[ "$scr_cols" -ge 58 ]]; then + chrono_width="large" + elif [[ "$scr_cols" -gt 40 ]]; then + chrono_width="medium" + else + chrono_width="small" + fi + + # Determine max length of divider string + scr_line_len=$(( scr_cols - 2 )) + [[ "$scr_line_len" -ge 58 ]] && scr_line_len="58" + scr_line_str=$(printf "%${scr_line_len}s") + scr_line_str="${scr_line_str// /—}" + 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 + + # Get CPU usage, only counting processes over 1% 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}') + cpu_mhz=$(lscpu | awk -F ":" '/MHz/ {print $2;exit}') + cpu_mhz=$(printf "%.0f" "${cpu_mhz//[[:space:]]/}") fi - - # Determine correct string format for CPU clock speed + + # Determine whether to display CPU clock speed as MHz or GHz 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="" + [[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(calcFunc "$cpu_mhz"/1000) GHz" fi - + # Determine colour for temperature if [[ -n "$temp_file" ]]; then if [[ "$temp_unit" == "C" ]]; then - cpu_temp=$(printf "%'.0fc\n" "$(calcFunc "$(< $temp_file) / 1000")") - + 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="";; @@ -249,13 +315,13 @@ get_sys_stats() { 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" - + 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")") - + 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="";; @@ -263,132 +329,199 @@ get_sys_stats() { 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" - + + 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")") + 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)) + + read -r -a 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" + ph_status="${COL_LIGHT_RED}Offline" fi - + if [[ "$DHCP_ACTIVE" == "true" ]]; then - ph_dhcp_num=$(wc -l 2> /dev/null < "/etc/pihole/dhcp.leases") + local ph_dhcp_range + + ph_dhcp_range=$(seq -s "|" -f "${DHCP_START%.*}.%g" "${DHCP_START##*.}" "${DHCP_END##*.}") + + # Count dynamic leases from available range, and not static leases + ph_dhcp_num=$(grep -cE "$ph_dhcp_range" "/etc/pihole/dhcp.leases") + ph_dhcp_percent=$(( ph_dhcp_num * 100 / ph_dhcp_max )) 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]}" + + mapfile -t 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]#* }" + queries_forwarded_raw="${stats_raw[11]#* }" + queries_cached_raw="${stats_raw[13]#* }" # 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}") + + 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}" + queries_cached_percentage=$(printf "%.0f\n" "$(calcFunc "$queries_cached_raw * 100 / ( $queries_forwarded_raw + $queries_cached_raw )")") + recent_blocked=$(pihole-FTL recentBlocked) + read -r -a top_ad_raw <<< "$(pihole-FTL "top-ads (1)")" + read -r -a top_domain_raw <<< "$(pihole-FTL "top-domains (1)")" + read -r -a top_client_raw <<< "$(pihole-FTL "top-clients (1)")" + + top_ad="${top_ad_raw[2]}" + top_domain="${top_domain_raw[2]}" + if [[ "${top_client_raw[3]}" ]]; then + top_client="${top_client_raw[3]}" + else + top_client="${top_client_raw[2]}" + fi fi } +get_strings() { + # Expand or contract strings depending on screen size + if [[ "$chrono_width" == "large" ]]; then + phc_str=" ${COL_DARK_GRAY}Pi-hole" + lte_str=" ${COL_DARK_GRAY}Admin" + ftl_str=" ${COL_DARK_GRAY}FTL" + api_str="${COL_LIGHT_RED}API Offline" + + host_info="$sys_type" + sys_info="$sys_throttle" + sys_info2="Active: $cpu_taskact of $cpu_tasks tasks" + used_str="Used: " + leased_str="Leased: " + domains_being_blocked=$(printf "%'.0f" "$domains_being_blocked") + ph_info="Blocking: $domains_being_blocked sites" + total_str="Total: " + else + phc_str=" ${COL_DARK_GRAY}PH" + lte_str=" ${COL_DARK_GRAY}Web" + ftl_str=" ${COL_DARK_GRAY}FTL" + api_str="${COL_LIGHT_RED}API Down" + ph_info="$domains_being_blocked blocked" + fi + + [[ "$sys_cores" -ne 1 ]] && sys_cores_txt="${sys_cores}x " + cpu_info="$sys_cores_txt$cpu_freq$cpu_temp_str" + ram_info="$used_str$(hrBytes "$ram_used") of $(hrBytes "$ram_total")" + disk_info="$used_str$(hrBytes "$disk_used") of $(hrBytes "$disk_total")" + + lan_info="Gateway: $net_gateway" + dhcp_info="$leased_str$ph_dhcp_num of $ph_dhcp_max" + + ads_info="$total_str$ads_blocked_today of $dns_queries_today" + dns_info="$dns_count DNS servers" + + [[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}" +} + 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}" + get_strings - 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" + # Strip excess development version numbers + if [[ "$ph_core_ver" != "-1" ]]; then + phc_ver_str="$phc_str: ${ph_core_ver%-*}${COL_NC}" + lte_ver_str="$lte_str: ${ph_lte_ver%-*}${COL_NC}" + ftl_ver_str="$ftl_str: ${ph_ftl_ver%-*}${COL_NC}" + else + phc_ver_str="$phc_str: $api_str${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 + + # Get refresh number + if [[ "$*" == *"-r"* ]]; then + num="$*" + num="${num/*-r /}" + num="${num/ */}" + num_str="Refresh set for every $num seconds" + else + num_str="" + fi + + clear + + # Remove exit message heading on third refresh + if [[ "$count" -le 2 ]] && [[ "$*" != *"-e"* ]]; then + echo -e " ${COL_LIGHT_GREEN}Pi-hole Chronometer${COL_NC} + $num_str + ${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC} + ${COL_DARK_GRAY}$scr_line_str${COL_NC}" + else + echo -e "|¯¯¯(¯)_|¯|_ ___|¯|___$phc_ver_str +| ¯_/¯|_| ' \/ _ \ / -_)$lte_ver_str +|_| |_| |_||_\___/_\___|$ftl_ver_str + ${COL_DARK_GRAY}$scr_line_str${COL_NC}" + fi + + printFunc " Hostname: " "$sys_name" "$host_info" + printFunc " Uptime: " "$sys_uptime" "$sys_info" + printFunc " Task Load: " "$sys_loadavg" "$sys_info2" + printFunc " CPU usage: " "$cpu_perc%" "$cpu_info" + printFunc " RAM usage: " "$ram_perc%" "$ram_info" + printFunc " HDD usage: " "$disk_perc" "$disk_info" + + if [[ "$scr_lines" -gt 17 ]] && [[ "$chrono_width" != "small" ]]; then + printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}" "$lan_info" + fi + + if [[ "$DHCP_ACTIVE" == "true" ]]; then + printFunc "DHCP usage: " "$ph_dhcp_percent%" "$dhcp_info" + fi + + printFunc " Pi-hole: " "$ph_status" "$ph_info" + printFunc " Ads Today: " "$ads_percentage_today%" "$ads_info" + printFunc "Local Qrys: " "$queries_cached_percentage%" "$dns_info" + + printFunc " Blocked: " "$recent_blocked" + printFunc "Top Advert: " "$top_ad" + + # Provide more stats on screens with more lines + if [[ "$scr_lines" -eq 17 ]]; then + if [[ "$DHCP_ACTIVE" == "true" ]]; then + printFunc "Top Domain: " "$top_domain" "last" + else + print_client="true" + fi + else + print_client="true" + fi + + if [[ -n "$print_client" ]]; then + printFunc "Top Domain: " "$top_domain" + printFunc "Top Client: " "$top_client" "last" + fi + + # Handle exit/refresh options + if [[ "$*" == *"-e"* ]]; then exit 0 else - if [[ -n "$1" ]]; then - sleep "${1}" + if [[ "$*" == *"-r"* ]]; then + sleep "$num" else sleep 5 fi @@ -409,14 +542,14 @@ helpFunc() { 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 } @@ -428,8 +561,8 @@ for var in "$@"; do case "$var" in "-j" | "--json" ) jsonFunc;; "-h" | "--help" ) helpFunc;; - "-r" | "--refresh" ) chronoFunc "$2";; - "-e" | "--exit" ) chronoFunc "exit";; + "-r" | "--refresh" ) chronoFunc "$@";; + "-e" | "--exit" ) chronoFunc "$@";; * ) helpFunc "?";; esac done From aad39c5ffc9ed879c3327224e1bf79d121615290 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Thu, 6 Jul 2017 19:25:56 -0500 Subject: [PATCH 55/75] add comments for nearly every line of code. --- automated install/basic-install.sh | 690 +++++++++++++++++++++++++---- 1 file changed, 597 insertions(+), 93 deletions(-) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index 3c6b77af..4a30461b 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -12,28 +12,49 @@ # pi-hole.net/donate # -# Install with this command (from your Pi): +# Install with this command (from your Linux machine): # # curl -L install.pi-hole.net | bash + +# -e option instructs bash to immediately exit if any command [1] has a non-zero exit status +# We do not want users to end up with a partially working install, so we exit the script +# instead of continuing the installation with something broken set -e + ######## VARIABLES ######### +# For better maintainability, we store as much information that can change in variables +# This allows us to make a change in one place that can propogate to all instances of the variable +# These variables should all be GLOBAL variables, written in CAPS +# Local variables will be in lowercase and will exist only within functions +# It's still a work in progress, so you may see some variance in this guideline until it is complete + +# We write to a temporary file before moving the log to the pihole folder tmpLog=/tmp/pihole-install.log instalLogLoc=/etc/pihole/install.log +# This is an important file as it contains information specific to the machine it's being installed on setupVars=/etc/pihole/setupVars.conf +# Pi-hole uses lighttpd as a Web server, and this is the config file for it lighttpdConfig=/etc/lighttpd/lighttpd.conf +# This is a file used for the colorized output coltable=/opt/pihole/COL_TABLE +# We store several other folders and webInterfaceGitUrl="https://github.com/pi-hole/AdminLTE.git" webInterfaceDir="/var/www/html/admin" piholeGitUrl="https://github.com/pi-hole/pi-hole.git" PI_HOLE_LOCAL_REPO="/etc/.pihole" +# These are the names of piholes files, stored in an array PI_HOLE_FILES=(chronometer list piholeDebug piholeLogFlush setupLCD update version gravity uninstall webpage) +# This folder is where the Pi-hole scripts will be installed PI_HOLE_INSTALL_DIR="/opt/pihole" useUpdateVars=false +# Pi-hole needs an IP address; to begin, these variables are empty since we don't know what the IP is until +# this script can run IPV4_ADDRESS="" IPV6_ADDRESS="" +# By default, query logging is enabled and the dashboard is set to be installed QUERY_LOGGING=true INSTALL_WEB=true @@ -51,13 +72,19 @@ r=$(( r < 20 ? 20 : r )) c=$(( c < 70 ? 70 : c )) ######## Undocumented Flags. Shhh ######## +# These are undocumented flags; some of which we can use when repairing an installation +# The runUnattended flag is one example of this skipSpaceCheck=false reconfigure=false runUnattended=false +# If the color table file exists, if [[ -f ${coltable} ]]; then + # source it source ${coltable} +# Othwerise, else + # Set these values so the installer can still run in color COL_NC='\e[0m' # No Color COL_LIGHT_GREEN='\e[1;32m' COL_LIGHT_RED='\e[1;31m' @@ -68,7 +95,8 @@ else OVER="\r\033[K" fi - +# A simple function that just echoes out our logo in ASCII format +# This lets users know that it is a Pi-hole, LLC product show_ascii_berry() { echo -e " ${COL_LIGHT_GREEN}.;;,. @@ -97,41 +125,63 @@ show_ascii_berry() { # Compatibility distro_check() { +# If apt-get is isntalled, then we know it's part of the Debian family if command -v apt-get &> /dev/null; then - #Debian Family - ############################################# + # Set some global variables here + # We don't set them earlier since the family might be Red Hat, so these values would be different PKG_MANAGER="apt-get" + # A variable to store the command used to update the package cache UPDATE_PKG_CACHE="${PKG_MANAGER} update" + # An array for something... 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" - # ######################################### - # fixes for dependency differences - # Debian 7 doesn't have iproute2 use iproute + # Some distros vary slightly so these fixes for dependencies may apply + # Debian 7 doesn't have iproute2 so if the dry run install is successful, if ${PKG_MANAGER} install --dry-run iproute2 > /dev/null 2>&1; then + # we can install it iproute_pkg="iproute2" + # Otherwise, else + # use iproute iproute_pkg="iproute" fi - # Prefer the php metapackage if it's there, fall back on the php5 packages + # We prefer the php metapackage if it's there if ${PKG_MANAGER} install --dry-run php > /dev/null 2>&1; then phpVer="php" + # If not, else + # fall back on the php5 packages phpVer="php5" fi - # ######################################### + + # Since our instal script is so large, we need several other programs to successfuly get a machine provisioned + # These programs are stored in an array so they can be looped through later INSTALLER_DEPS=(apt-utils dialog debconf dhcpcd5 git ${iproute_pkg} whiptail) + # Pi-hole itself has several dependencies that also need to be installed PIHOLE_DEPS=(bc cron curl dnsmasq dnsutils iputils-ping lsof netcat sudo unzip wget) + # The Web dashboard has some that also need to be installed + # It's useful to separate the two since our repos are also setup as "Core" code and "Web" code PIHOLE_WEB_DEPS=(lighttpd ${phpVer}-common ${phpVer}-cgi) + # The Web server user, LIGHTTPD_USER="www-data" + # group, LIGHTTPD_GROUP="www-data" + # and config file LIGHTTPD_CFG="lighttpd.conf.debian" + # The DNS server user DNSMASQ_USER="dnsmasq" - test_dpkg_lock() { +# A function to check... +test_dpkg_lock() { + # An iterator used for counting loop iterations i=0 + # fuser is a program to show which processes use the named files, sockets, or filesystems + # So while the command is true while fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do + # Wait half a second sleep 0.5 + # and increase the iterator ((i=i+1)) done # Always return success, since we only return if there is no @@ -139,15 +189,16 @@ if command -v apt-get &> /dev/null; then return 0 } +# If apt-get is not found, check for rpm to see if it's a Red Hat family OS elif command -v rpm &> /dev/null; then - # Fedora Family + # Then check if dnf or yum is the package manager if command -v dnf &> /dev/null; then PKG_MANAGER="dnf" else PKG_MANAGER="yum" fi -# Fedora and family update cache on every PKG_INSTALL call, no need for a separate update. + # Fedora and family update cache on every PKG_INSTALL call, no need for a separate update. UPDATE_PKG_CACHE=":" PKG_INSTALL=(${PKG_MANAGER} install -y) PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l" @@ -162,113 +213,176 @@ elif command -v rpm &> /dev/null; then LIGHTTPD_CFG="lighttpd.conf.fedora" DNSMASQ_USER="nobody" +# If neither apt-get or rmp/dnf are not found else + # it's not an OS we can support, echo -e " ${CROSS} OS distribution not supported" + # so exit the installer exit fi } +# A function for checking if a folder is a git repository is_repo() { - # Use git to check if directory is currently under VCS, return the value 128 - # if directory is not a repo. Return 1 if directory does not exist. + # Use a named, local variable instead of the vague $1, which is the first arguement passed to this function + # These local variables should always be lowercase local directory="${1}" + # A local variabled for the current directory local curdir + # A variable to store the return code local rc - + # Assign the current directory variable by using pwd curdir="${PWD}" + # If the first argument passed to this function is a directory, if [[ -d "${directory}" ]]; then - # git -C is not used here to support git versions older than 1.8.4 + # move into the directory cd "${directory}" + # Use git to check if the folder is a repo + # git -C is not used here to support git versions older than 1.8.4 git status --short &> /dev/null || rc=$? + # If the command was not successful, else - # non-zero return code if directory does not exist + # Set a non-zero return code if directory does not exist rc=1 fi + # Move back into the directory the user started in cd "${curdir}" + # Return the code; if one is not set, return 0 return "${rc:-0}" } +# A function to clone a repo make_repo() { + # Set named variables for better readability local directory="${1}" local remoteRepo="${2}" + # The message to display when this function is running str="Clone ${remoteRepo} into ${directory}" + # Display the message and use the color table to preface the message with an "info" indicator echo -ne " ${INFO} ${str}..." - # Clean out the directory if it exists for git to clone into + # If the directory exists, if [[ -d "${directory}" ]]; then + # delete everything in it so git can clone into it rm -rf "${directory}" fi + # Clone the repo and return the return code from this command git clone -q --depth 1 "${remoteRepo}" "${directory}" &> /dev/null || return $? + # Show a colored message showing it's status echo -e "${OVER} ${TICK} ${str}" + # Always return 0? Not sure this is correct return 0 } +# We need to make sure the repos are up-to-date so we can effectively install Clean out the directory if it exists for git to clone into update_repo() { + # Use named, local variables + # As you can see, these are the same variable names used in the last function, + # but since they are local, their scope does not go beyond this function + # This helps prevent the wrong value from being assigned if you were to set the variable as a GLOBAL one local directory="${1}" local curdir + # A variable to store the message we want to display; + # Again, it's useful to store these in variables in case we need to reuse or change the message; + # we only need to make one change here local str="Update repo in ${1}" + + # Make sure we know what directory we are in so we can move back into it curdir="${PWD}" + # Move into the directory that was passed as an argument cd "${directory}" &> /dev/null || return 1 - # Pull the latest commits + # Let the user know what's happening echo -ne " ${INFO} ${str}..." + # Stash any local commits as they conflict with our working code git stash --all --quiet &> /dev/null || true # Okay for stash failure git clean --quiet --force -d || true # Okay for already clean directory + # Pull the latest commits git pull --quiet &> /dev/null || return $? + # Show a completion message echo -e "${OVER} ${TICK} ${str}" + # Move back into the oiginal directory cd "${curdir}" &> /dev/null || return 1 return 0 } +# A function that combines the functions previously made getGitFiles() { - # Setup git repos for directory and repository passed - # as arguments 1 and 2 + # Setup named variables for the git repos + # We need the directory local directory="${1}" + # as well as the repo URL local remoteRepo="${2}" + # A local varible containing the message to be displayed local str="Check for existing repository in ${1}" + # Show the message echo -ne " ${INFO} ${str}..." + # Check if the directory is a repository if is_repo "${directory}"; then + # Show that we're checking it echo -e "${OVER} ${TICK} ${str}" + # Update the repo, returning an error message on failure update_repo "${directory}" || { echo -e "\n ${COL_LIGHT_RED}Error: Could not update local repository. Contact support.${COL_NC}"; exit 1; } + # If it's not a .git repo, else + # Show an error echo -e "${OVER} ${CROSS} ${str}" + # Attempt to make the repository, showing an error on falure make_repo "${directory}" "${remoteRepo}" || { echo -e "\n ${COL_LIGHT_RED}Error: Could not update local repository. Contact support.${COL_NC}"; exit 1; } fi + # echo a blank line echo "" + # and return success? return 0 } +# Reset a repo to get rid of any local changed resetRepo() { + # Use named varibles for arguments local directory="${1}" - + # Move into the directory cd "${directory}" &> /dev/null || return 1 + # Store the message in a varible str="Resetting repository within ${1}..." + # Show the message echo -ne " ${INFO} ${str}" + # Use git to remove the local changes git reset --hard &> /dev/null || return $? + # And show the status echo -e "${OVER} ${TICK} ${str}" + # Returning success anyway? return 0 } +# We need to know the IPv4 information so we can effectively setup the DNS server +# Without this information, we won't know where to Pi-hole will be found find_IPv4_information() { + # Named, local variables local route - # Find IP used to route to outside world + # Find IP used to route to outside world by checking the the route to Google's public DNS server route=$(ip route get 8.8.8.8) + # Use awk to strip out just the interface device as it is used in future commands IPv4dev=$(awk '{for (i=1; i<=NF; i++) if ($i~/dev/) print $(i+1)}' <<< "${route}") + # Get just the IP address IPv4bare=$(awk '{print $7}' <<< "${route}") + # Append the CIDR notation to the IP address IPV4_ADDRESS=$(ip -o -f inet addr show | grep "${IPv4bare}" | awk '{print $4}' | awk 'END {print}') + # Get the default gateway (the way to reach the Internet) IPv4gw=$(awk '{print $3}' <<< "${route}") } +# Get available interfaces that are UP get_available_interfaces() { - # Get available UP interfaces. + # There may be more than one so it's all stored in a variable availableInterfaces=$(ip --oneline link show up | grep -v "lo" | awk '{print $2}' | cut -d':' -f1 | cut -d'@' -f1) } +# A function for displaying the dialogs the user sees when first running the installer welcomeDialogs() { - # Display the welcome dialog + # Display the welcome dialog using an approriately sized window via the calculation conducted earlier in the script whiptail --msgbox --backtitle "Welcome" --title "Pi-hole automated installer" "\n\nThis installer will transform your device into a network-wide ad blocker!" ${r} ${c} - # Support for a part-time dev + # Request that users donate if they enjoy the software since we all work on it in our free time whiptail --msgbox --backtitle "Plea" --title "Free and open source" "\n\nThe Pi-hole is free, but powered by your donations: http://pi-hole.net/donate" ${r} ${c} # Explain the need for a static address @@ -277,43 +391,54 @@ welcomeDialogs() { In the next section, you can choose to use your current network settings (DHCP) or to manually edit them." ${r} ${c} } +# We need to make sure there is enough space before installing, so there is a function to check this 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. local str="Disk space check" + # Reqired space in KB local required_free_kilobytes=51200 + # Calculate existing free space on this machine local existing_free_kilobytes=$(df -Pk | grep -m1 '\/$' | awk '{print $4}') - # - Unknown free disk space , not a integer + # If the existing space is not an integer, if ! [[ "${existing_free_kilobytes}" =~ ^([0-9])+$ ]]; then + # show an error that we can't determine the free space 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}