From 6fa00e7cc86a8fb661ab3343c67b2d30e5d583f1 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Sat, 20 May 2017 01:34:13 -0500 Subject: [PATCH 001/116] 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 002/116] 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 003/116] 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 004/116] 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 005/116] 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 006/116] 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 007/116] 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 008/116] 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 009/116] 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 010/116] 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 011/116] 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 012/116] 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 013/116] 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 014/116] 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 015/116] 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 016/116] 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 017/116] 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 018/116] 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 019/116] 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 020/116] 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 021/116] 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 022/116] 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 023/116] 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 024/116] 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 025/116] 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 026/116] 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 027/116] 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 028/116] 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 029/116] 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 030/116] 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 031/116] 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 032/116] 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 033/116] 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 034/116] 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 035/116] 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 036/116] 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 037/116] 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 038/116] 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 039/116] 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 040/116] 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 041/116] 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 042/116] 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 ecde2225122904a89543712ec8f2b0fd1da26ff6 Mon Sep 17 00:00:00 2001 From: Adam Warner Date: Tue, 20 Jun 2017 22:17:41 +0100 Subject: [PATCH 043/116] [Staging] 3.1 (#1502) * Fix handling of wildcard help text * Rewrite help text for better handling of params * Replace misleading letter variable * stash changes on branch switch, else it fails if any changes have been made. * Make changes according to comment in #1384 * Update queryFunc() * Allow scanList() to search files using a wildcard by removing quotes wrapped around `${list}` * scanList() will not provide a domain ouput on each string if exact is specified (`grep -l`) * Remove unused processWildcards() function * Return a message if no domain is specified * IDN domains are converted to punycode when running a `pihole -q` search if the `python` package is available, otherwise will revert to current behaviour * Scan Blacklist & Wildcards first, exiting from search if a match is found (Fixes #1330) * Use one `grep` subshell to search for all "*.domains" lists at once (opposed to looping to get every matching file name, and then spawning a `grep` instance for every matching file) * queryFunc() will not return "(0 results)" output from files where no match is found * Sort results based off list number * Return a message if no results are found * Update basic-install.sh * Update block page. Allow for setupVars setting of CUSTOMBLOCKPAGE (bool) to prevent it being overwritten * simplify * further simplify * fix inteliJ IDEA complaints * even further simplify * tidy up output * revert line, looks tidyer * clarify * Revert "Ensure any changes to blocking page are updated." * We test for dpkg lock on line 830 directly, no need for the check also in the template section. Signed-off-by: Dan Schaper * Display FTL version & version.sh rewrite While testing to make sure `pihole -v` would output `pihole-FTL version`, I noticed some options didn't work how I expected them to. For example, if I use `pihole -v -p`, I would expect to see the version output of Pi-hole Core. Instead, I'm informed that it's an invalid option. I've had the following things in mind while rewriting this: * I'm operating under the assumption that FTL is only installed if the Admin Console is (Line 113 exit 0) * I have modified the help text to only output with `pihole -v --help` * I have modified all output to be more similar to the output style of `grep` and `curl` (Ditching ":::") Testing output: ``` w3k@MCT:~$ pihole -v Pi-hole version is v3.0.1-14-ga928cd3 (Latest: v3.0.1) Admin Console version is v3.0-9-g3760482 (Latest: v3.0.1) FTL version is v2.6.2 (Latest: v2.6.2) w3k@MCT:~$ pihole -v -c Current Pi-hole version is v3.0.1-14-ga928cd3 Current Admin Console version is v3.0-9-g3760482 Current FTL version is v2.6.2 w3k@MCT:~$ pihole -v -l Latest Pi-hole version is v3.0.1 Latest Admin Console version is v3.0.1 Latest FTL version is v2.6.2 w3k@MCT:~$ pihole -v -p --hash Current Pi-hole hash is a928cd3 w3k@MCT:~$ pihole -v -a --hash Current Admin Console hash is 3760482 w3k@MCT:~$ pihole -v --help Usage: pihole -v [REPO | OPTION] [OPTION] Show Pi-hole, Web Admin & FTL versions w3k@MCT:~$ pihole -v -foo Invalid Option! ``` * Update -h to work as --hash Also provide error output as per https://github.com/pi-hole/pi-hole/pull/1447#issuecomment-300600093 * Perform EXACT searches on HOSTS lists correctly `\s` on the end may be overkill, but it is the existing scanList() behaviour. * Fixed indentation * Minimise string duplication & other minor changes Instead of duplicating output strings, rewrite core/web/ftlOutput() into one neat versionOutput(). * Modified syntax to be valid for Shellcheck * Log and echo gateway responses * Update queryFunc() to search Whitelist If there is a match in Whitelist/Blacklist/Wildcards, `[ ! -t 1 ]` will cause the search to end if the terminal is closed when the script is called. This has the intended effect of allowing a user to search for a W/B/W domain (as well as all the adlists it's found in) using `pihole -q` via Terminal, but the script will stop searching after a W/B/W match when called by the block page. * Wrap in double brackets * Provide remote hashes for version.sh * Provide remote hashes for comparison * Use double braces for all conditions (for consistency) * Suppress potential "cd" error output * Provide "not applicable" output upon any hash request for FTL * whitelist on website blocked doesnt work (#1452) Since Pi-hole redirects ad domains to itself, accessing the script via de.ign.com is the same as pi.hole in this case. The fix should be as simple as adding a / before admin on this line. * Solve piholeLogFlush.sh having to be issued 2 x to clear logs (#1460) Simplified the command -v syntax, and added a sleep 3 timer to the first execution of the log rotation. The second execution was being issued while the first was still running, thus it would fail and you would have to issue the "Flush Logs" command a second time. * Use `echo "ABC" | pihole tricorder` to upload to Pi-hole's medical tricorder. Uses SSL if available. * Update list.sh I believe this has feature parity with `sed /foo/ Id` but also supports busybox, and my alpine docker ;) * Document `sed` substitution for user readability Comment the oneliner with explanations of what each step does. * Update Help Output (#1467) * File consistency * Tabs to 2 spaces * Corrected indenting * Double braced conditionals * Quoted variables within conditionals * Standardise core help text * Added help text for disable command * Added help text for logging command * Clean up * Fixed certain new lines and spaces * Sync with development branch * Formatting consistency * Tabs to 2 spaces * Corrected indenting * Double braced conditionals * Quoted variables within conditionals * Fixed certain newlines and spaces * Admin help text * Added help text for interface command * Sync with development branch * Formatting consistency * Tabs to 2 spaces * Fixed some wording * Fixed certain spaces * Formatting consistency * Minor wording changes * Tabs to 2 spaces * Corrected indenting * Double braced conditionals * Quoted variables within conditionals * Fixed certain newlines and spaces * Blacklist help text * Formatting consistency * Tabs to 2 spaces * Corrected indenting * Cronometer help text * Formatting consistency * Fixed certain newlines and spaces * Corrected indenting * Checkout warning alteration * Add checkout help text * Corrected help output * Show help for "pihole -a -i --help" * Fix "pihole disable --help" and "pihole -l --help" * Show help for "pihole -v -h" * Indent output text * Minor help text change * Show help for "pihole checkout --help" * Tricorder: Insecure Opt-out * Check to see if Tricorder is being called directly * Provide opt-out for insecure transmission of debug log * Remove mention of internal function from help menu * :taco: is the new :shipit: squirrel * Wording changes and bug fix * Fix wildcard help text * -wild is not a valid option since we're already using -wild * Fix logrotation: manual flushing should be done twice, but automated rotation at midnight should only be done *once*! * Print echos only when manual flushing is requested * Add "quiet" mode + update comments in the cron file * Confirm Tricorder is online * Scan port 9998 to confirm the availability of "tricorder.pi-hole.net" * Exit codes for upload process * Formatting consistency * Add link to Windows DNS Swapper See #1400 * Install loopback firewall rules for FTL (#1419) * Install loopback firewall rules for FTL * FirewallD FTL ports Signed-off-by: Dan Schaper * Remove firewallD FTL local rules. Local rules should not be blocked in firewallD, not requred for internal service FTD> * Reinstate https rules, and delete FTL rules Fixes earlier commit. * Retrieve local repos on repair (#1481) * Retrieve local repos on repair * Change conditional to check for repair * Change wording of Update/Reconfigure message * Fixed indenting * Perform "git reset --hard" on reconfigure * Change directory before trying to reset repository. Fixes #1489 * No need to `cd $PWD` as it doesn't affect flow of caller script. Signed-off-by: Dan Schaper * Refine output of password status in basic-install.sh:displayFinalMessage(). Fixes #1488 (#1490) * Rewrite Chronometer to output more stats * Fix output IPv4 addr when removing CIDR notation (#1498) * Move wildcards file if blocking is disabled (#1495) * Move wildcards file if blocking is diabled * Delete newline * Roll back merge #1417 (#1494) * Update ISSUE_TEMPLATE.md * Remove Question option * Prefer ULA over GUA addresses [IPv6] (#1508) * On installs with GUA and ULA's we should prefer ULA's as it's been demonstrated that GUA's can and often are rotated by ISPs. Fixes #1473 * Add test for link-local address detection * Add ULA-only and GUA-only tests * Add test_IPv6_GUA_ULA_test and test_IPv6_ULA_GUA_test * Add "" * Add mock_command_2 command that can mock a command with more than one argument (as "ip -6 address") and result multiple lines of results * Make mock_command_2 more similar to the original mock_command * Correct comments * Fixed remaining comments * Fixed one last comment... * Fixed a comment... * Add weekly logrotation of FTL's log (#1509) * Update LICENSE of the project to EUPL v1.2 * Make clear that NO is the default if the user just hits return (#1514) * Add tricorderFunc back as usable function (#1515) As per #1464 * Don't update FTL when there is a core update (as this will update FTL a second time). Fixes #1516 * Add FTL tests to the test suite (#1510) * Add first version of FTL tests * Wait one second to allow FTL to start up and analyze our mock log * Add test_FTL_telnet_statistics * Added test_FTL_telnet_top_clients * Add test_FTL_telnet_top_domains * Revert "Add FTL tests to the test suite (#1510)" (#1519) This reverts commit cf6a1ac9adb4e26570cc5da7c8be628080f37e0f. * Trim version output when update is successful (#1527) * Change ownership of /etc/pihole to user/group pihole. Fixes #1529 (#1530) * Delete temporary files after installing the FTL binary. Fixes #1525 * Change from admin to approvers teams * Introduce new file black.list for blacklist content * Add "pihole -g -b" to *only* update black.list (saves a bunch of time when adding/changing only blacklisted files - won'tdownload lal lists, but only processes the blacklist and restars dnsmasq) * Remove useless cat * Improve displayed messages and overall logic * Disable black.list on "pihole disable" * cp + rm === mv (well, almost) --- .github/ISSUE_TEMPLATE.md | 2 +- .pullapprove.yml | 4 +- LICENSE | 119 +++---- README.md | 1 + advanced/01-pihole.conf | 1 + advanced/Scripts/chronometer.sh | 479 ++++++++++++++++++++++++----- advanced/Scripts/list.sh | 311 +++++++++---------- advanced/Scripts/piholeCheckout.sh | 32 +- advanced/Scripts/piholeDebug.sh | 8 +- advanced/Scripts/piholeLogFlush.sh | 43 ++- advanced/Scripts/update.sh | 13 +- advanced/Scripts/version.sh | 165 ++++++---- advanced/Scripts/webpage.sh | 187 +++++------ advanced/index.php | 2 +- advanced/logrotate | 11 + advanced/pihole-FTL.service | 2 +- advanced/pihole.cron | 7 +- automated install/basic-install.sh | 98 ++++-- gravity.sh | 109 ++++--- pihole | 207 +++++++++---- test/test_automated_install.py | 76 +++++ 21 files changed, 1227 insertions(+), 650 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 3014625b..23e67795 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -9,7 +9,7 @@ _{replace this text with a number from 1 to 10, with 1 being not familiar, and 10 being very familiar}_ --- -**[FEATURE REQUEST | QUESTION | OTHER]:** +**[BUG REPORT | OTHER]:** Please [submit your feature request here](https://discourse.pi-hole.net/c/feature-requests), so it is votable by the community. It's also easier for us to track. diff --git a/.pullapprove.yml b/.pullapprove.yml index 39566b34..30888234 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -10,7 +10,7 @@ group_defaults: reset_on_push: enabled: true reject_value: -2 - approve_regex: '^(Approved|:shipit:|:\+1:|Engage)' + approve_regex: '^(Approved|:shipit:|:\+1:|Engage|:taco:)' reject_regex: '^(Rejected|:-1:|Borg)' author_approval: auto: true @@ -35,4 +35,4 @@ groups: - master required: 4 teams: - - admin + - approvers diff --git a/LICENSE b/LICENSE index 9fddaad1..9ce6e5b0 100644 --- a/LICENSE +++ b/LICENSE @@ -12,81 +12,63 @@ This license applies to the whole project EXCEPT: The licenses that existed prior to this change have remained intact. ------------------------------------------------------------- +EUROPEAN UNION PUBLIC LICENCE v. 1.2 -European Union Public Licence -V. 1.1 +EUPL © the European Union 2007, 2016 -EUPL (C) the European Community 2007 - -This European Union Public Licence (the "EUPL") applies to the Work or Software (as defined below) which is provided under the terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such use is covered by a right of the copyright holder of the Work). - -The Original Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following notice immediately following the copyright notice for the Original Work: - -Licensed under the EUPL V.1.1 - -or has expressed by any other mean his willingness to license under the EUPL. +This European Union Public Licence (the EUPL) applies to the Work (as defined below) which is provided under the terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such use is covered by a right of the copyright holder of the Work). +The Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following notice immediately following the copyright notice for the Work: +Licensed under the EUPL +or has expressed by any other means his willingness to license under the EUPL. 1. Definitions In this Licence, the following terms have the following meaning: - The Licence: this Licence. - -- The Original Work or the Software: the software distributed and/or communicated by the Licensor under this Licence, available as Source Code and also as Executable Code as the case may be. - +- The Original Work: the work or software distributed or communicated by the Licensor under this Licence, available as Source Code and also as Executable Code as the case may be. - Derivative Works: the works or software that could be created by the Licensee, based upon the Original Work or modifications thereof. This Licence does not define the extent of modification or dependence on the Original Work required in order to classify a work as a Derivative Work; this extent is determined by copyright law applicable in the country mentioned in Article 15. - -- The Work: the Original Work and/or its Derivative Works. - +- The Work: the Original Work or its Derivative Works. - The Source Code: the human-readable form of the Work which is the most convenient for people to study and modify. - - The Executable Code: any code which has generally been compiled and which is meant to be interpreted by a computer as a program. - -- The Licensor: the natural or legal person that distributes and/or communicates the Work under the Licence. - +- The Licensor: the natural or legal person that distributes or communicates the Work under the Licence. - Contributor(s): any natural or legal person who modifies the Work under the Licence, or otherwise contributes to the creation of a Derivative Work. - -- The Licensee or "You": any natural or legal person who makes any usage of the Software under the terms of the Licence. - -- Distribution and/or Communication: any act of selling, giving, lending, renting, distributing, communicating, transmitting, or otherwise making available, on-line or off-line, copies of the Work or providing access to its essential functionalities at the disposal of any other natural or legal person. +- The Licensee or You: any natural or legal person who makes any usage of the Work under the terms of the Licence. +- Distribution or Communication: any act of selling, giving, lending, renting, distributing, communicating, transmitting, or otherwise making available, online or offline, copies of the Work or providing access to its essential functionalities at the disposal of any other natural or legal person. 2. Scope of the rights granted by the Licence -The Licensor hereby grants You a world-wide, royalty-free, non-exclusive, sub-licensable licence to do the following, for the duration of copyright vested in the Original Work: - +The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, sublicensable licence to do the following, for the duration of copyright vested in the Original Work: - use the Work in any circumstance and for all usage, - reproduce the Work, -- modify the Original Work, and make Derivative Works based upon the Work, +- modify the Work, and make Derivative Works based upon the Work, - communicate to the public, including the right to make available or display the Work or copies thereof to the public and perform publicly, as the case may be, the Work, - distribute the Work or copies thereof, - lend and rent the Work or copies thereof, -- sub-license rights in the Work or copies thereof. - +- sublicense rights in the Work or copies thereof. Those rights can be exercised on any media, supports and formats, whether now known or later invented, as far as the applicable law permits so. - In the countries where moral rights apply, the Licensor waives his right to exercise his moral right to the extent allowed by law in order to make effective the licence of the economic rights here above listed. - -The Licensor grants to the Licensee royalty-free, non exclusive usage rights to any patents held by the Licensor, to the extent necessary to make use of the rights granted on the Work under this Licence. +The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to any patents held by the Licensor, to the extent necessary to make use of the rights granted on the Work under this Licence. 3. Communication of the Source Code -The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to distribute and/or communicate the Work. +The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to distribute or communicate the Work. 4. Limitations on copyright -Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the exclusive rights of the rights owners in the Original Work or Software, of the exhaustion of those rights or of other applicable limitations thereto. +Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the exclusive rights of the rights owners in the Work, of the exhaustion of those rights or of other applicable limitations thereto. 5. Obligations of the Licensee The grant of the rights mentioned above is subject to some restrictions and obligations imposed on the Licensee. Those obligations are the following: -Attribution right: the Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the Licence with every copy of the Work he/she distributes and/or communicates. The Licensee must cause any Derivative Work to carry prominent notices stating that the Work has been modified and the date of modification. +Attribution right: The Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the Licence with every copy of the Work he/she distributes or communicates. The Licensee must cause any Derivative Work to carry prominent notices stating that the Work has been modified and the date of modification. -Copyleft clause: If the Licensee distributes and/or communicates copies of the Original Works or Derivative Works based upon the Original Work, this Distribution and/or Communication will be done under the terms of this Licence or of a later version of this Licence unless the Original Work is expressly distributed only under this version of the Licence. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the Work or Derivative Work that alter or restrict the terms of the Licence. +Copyleft clause: If the Licensee distributes or communicates copies of the Original Works or Derivative Works, this Distribution or Communication will be done under the terms of this Licence or of a later version of this Licence unless the Original Work is expressly distributed only under this version of the Licence - for example by communicating EUPL v. 1.2 only. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the Work or Derivative Work that alter or restrict the terms of the Licence. -Compatibility clause: If the Licensee Distributes and/or Communicates Derivative Works or copies thereof based upon both the Original Work and another work licensed under a Compatible Licence, this Distribution and/or Communication can be done under the terms of this Compatible Licence. For the sake of this clause, "Compatible Licence" refers to the licences listed in the appendix attached to this Licence. Should the Licensee’s obligations under the Compatible Licence conflict with his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail. +Compatibility clause: If the Licensee Distributes or Communicates Derivative Works or copies thereof based upon both the Work and another work licensed under a Compatible Licence, this Distribution or Communication can be done under the terms of this Compatible Licence. For the sake of this clause, Compatible Licence refers to the licences listed in the appendix attached to this Licence. Should the Licensee's obligations under the Compatible Licence conflict with his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail. -Provision of Source Code: When distributing and/or communicating copies of the Work, the Licensee will provide a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available for as long as the Licensee continues to distribute and/or communicate the Work. +Provision of Source Code: When distributing or communicating copies of the Work, the Licensee will provide a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available for as long as the Licensee continues to distribute or communicate the Work. Legal Protection: This Licence does not grant permission to use the trade names, trademarks, service marks, or names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the copyright notice. @@ -100,10 +82,8 @@ Each time You accept the Licence, the original Licensor and subsequent Contribut 7. Disclaimer of Warranty -The Work is a work in progress, which is continuously improved by numerous contributors. It is not a finished work and may therefore contain defects or "bugs" inherent to this type of software development. - -For the above reason, the Work is provided under the Licence on an "as is" basis and without warranties of any kind concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this Licence. - +The Work is a work in progress, which is continuously improved by numerous Contributors. It is not a finished work and may therefore contain defects or bugs inherent to this type of development. +For the above reason, the Work is provided under the Licence on an as is basis and without warranties of any kind concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this Licence. This disclaimer of warranty is an essential part of the Licence and a condition for the grant of any rights to the Work. 8. Disclaimer of Liability @@ -112,56 +92,55 @@ Except in the cases of wilful misconduct or damages directly caused to natural p 9. Additional agreements -While distributing the Original Work or Derivative Works, You may choose to conclude an additional agreement to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or services consistent with this Licence. However, in accepting such obligations, You may act only on your own behalf and on your sole responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by the fact You have accepted any such warranty or additional liability. +While distributing the Work, You may choose to conclude an additional agreement, defining obligations or services consistent with this Licence. However, if accepting obligations, You may act only on your own behalf and on your sole responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by the fact You have accepted any warranty or additional liability. 10. Acceptance of the Licence -The provisions of this Licence can be accepted by clicking on an icon "I agree" placed under the bottom of a window displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms and conditions. - -Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution and/or Communication by You of the Work or copies thereof. +The provisions of this Licence can be accepted by clicking on an icon I agree placed under the bottom of a window displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms and conditions. +Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution or Communication by You of the Work or copies thereof. 11. Information to the public -In case of any Distribution and/or Communication of the Work by means of electronic communication by You (for example, by offering to download the Work from a remote location) the distribution channel or media (for example, a website) must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence and the way it may be accessible, concluded, stored and reproduced by the Licensee. +In case of any Distribution or Communication of the Work by means of electronic communication by You (for example, by offering to download the Work from a remote location) the distribution channel or media (for example, a website) must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence and the way it may be accessible, concluded, stored and reproduced by the Licensee. 12. Termination of the Licence The Licence and the rights granted hereunder will terminate automatically upon any breach by the Licensee of the terms of the Licence. - Such a termination will not terminate the licences of any person who has received the Work from the Licensee under the Licence, provided such persons remain in full compliance with the Licence. 13. Miscellaneous -Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the Work licensed hereunder. - -If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or enforceability of the Licence as a whole. Such provision will be construed and/or reformed so as necessary to make it valid and enforceable. - -The European Commission may publish other linguistic versions and/or new versions of this Licence, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence. New versions of the Licence will be published with a unique version number. - +Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the Work. +If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or enforceability of the Licence as a whole. Such provision will be construed or reformed so as necessary to make it valid and enforceable. +The European Commission may publish other linguistic versions or new versions of this Licence or updated versions of the Appendix, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence. New versions of the Licence will be published with a unique version number. All linguistic versions of this Licence, approved by the European Commission, have identical value. Parties can take advantage of the linguistic version of their choice. 14. Jurisdiction -Any litigation resulting from the interpretation of this License, arising between the European Commission, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice of the European Communities, as laid down in article 238 of the Treaty establishing the European Community. - -Any litigation arising between Parties, other than the European Commission, and resulting from the interpretation of this License, will be subject to the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business. +Without prejudice to specific agreement between parties, +- any litigation resulting from the interpretation of this License, arising between the European Union institutions, bodies, offices or agencies, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice of the European Union, as laid down in article 272 of the Treaty on the Functioning of the European Union, +- any litigation arising between other parties and resulting from the interpretation of this License, will be subject to the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business. 15. Applicable Law -This Licence shall be governed by the law of the European Union country where the Licensor resides or has his registered office. - -This licence shall be governed by the Belgian law if: - -- a litigation arises between the European Commission, as a Licensor, and any Licensee; -- the Licensor, other than the European Commission, has no residence or registered office inside a European Union country. - +Without prejudice to specific agreement between parties, +- this Licence shall be governed by the law of the European Union Member State where the Licensor has his seat, resides or has his registered office, +- this licence shall be governed by Belgian law if the Licensor has no seat, residence or registered office inside a European Union Member State. === + Appendix -"Compatible Licences" according to article 5 EUPL are: -- GNU General Public License (GNU GPL) v. 2 +Compatible Licences according to Article 5 EUPL are: +- GNU General Public License (GPL) v. 2, v. 3 +- GNU Affero General Public License (AGPL) v. 3 - Open Software License (OSL) v. 2.1, v. 3.0 -- Common Public License v. 1.0 -- Eclipse Public License v. 1.0 -- Cecill v. 2.0 +- Eclipse Public License (EPL) v. 1.0 +- CeCILL v. 2.0, v. 2.1 +- Mozilla Public Licence (MPL) v. 2 +- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 +- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for works other than software +- European Union Public Licence (EUPL) v. 1.1, v. 1.2 +- Québec Free and Open-Source Licence - Reciprocity (LiLiQ-R) or Strong Reciprocity (LiLiQ-R+) +- The European Commission may update this Appendix to later versions of the above licences without producing a new version of the EUPL, as long as they provide the rights granted in Article 2 of this Licence and protect the covered Source Code from exclusive appropriation. +- All other changes or additions to this Appendix require the production of a new EUPL version. diff --git a/README.md b/README.md index 75c548e5..6f8813fa 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,7 @@ You can view [real-time stats](https://discourse.pi-hole.net/t/how-do-i-view-my- - [Let your blink1 device blink when Pi-hole filters ads](https://gist.github.com/elpatron68/ec0b4c582e5abf604885ac1e068d233f) - [Pi-hole Prometheus exporter](https://github.com/nlamirault/pihole_exporter): a [Prometheus](https://prometheus.io/) exporter for Pi-hole - [Pi-hole Droid - open source Android client](https://github.com/friimaind/pi-hole-droid) +- [Windows DNS Swapper](https://github.com/roots84/DNS-Swapper), see [#1400](https://github.com/pi-hole/pi-hole/issues/1400) ## Coverage diff --git a/advanced/01-pihole.conf b/advanced/01-pihole.conf index 1b157f88..79735c15 100644 --- a/advanced/01-pihole.conf +++ b/advanced/01-pihole.conf @@ -22,6 +22,7 @@ addn-hosts=/etc/pihole/gravity.list addn-hosts=/etc/pihole/local.list +addn-hosts=/etc/pihole/black.list domain-needed diff --git a/advanced/Scripts/chronometer.sh b/advanced/Scripts/chronometer.sh index 67ff495b..d9b7d05b 100755 --- a/advanced/Scripts/chronometer.sh +++ b/advanced/Scripts/chronometer.sh @@ -8,101 +8,428 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. -#Functions############################################################################################################## -piLog="/var/log/pihole.log" -gravity="/etc/pihole/gravity.list" - -. /etc/pihole/setupVars.conf - -function GetFTLData { +# Retrieve stats from FTL engine +pihole-FTL() { + ftl_port=$(cat /var/run/pihole-FTL.port 2> /dev/null) + if [[ -n "$ftl_port" ]]; then # Open connection to FTL - exec 3<>/dev/tcp/localhost/"$(cat /var/run/pihole-FTL.port)" + exec 3<>"/dev/tcp/localhost/$ftl_port" # Test if connection is open - if { >&3; } 2> /dev/null; then - # Send command to FTL - echo -e ">$1" >&3 + if { "true" >&3; } 2> /dev/null; then + # Send command to FTL + echo -e ">$1" >&3 - # Read input - read -r -t 1 LINE <&3 - until [ ! $? ] || [[ "$LINE" == *"EOM"* ]]; do - echo "$LINE" >&1 - read -r -t 1 LINE <&3 - done + # Read input + read -r -t 1 LINE <&3 + until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do + echo "$LINE" >&1 + read -r -t 1 LINE <&3 + done - # Close connection - exec 3>&- - exec 3<&- + # Close connection + exec 3>&- + exec 3<&- fi + else + echo -e "${COL_LIGHT_RED}FTL offline${COL_NC}" + fi } -outputJSON() { - get_summary_data - echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}" +# Print spaces to align right-side content +printFunc() { + txt_len="${#2}" + + # Reduce string length when using colour code + [ "${2:0:1}" == "" ] && txt_len=$((txt_len-7)) + + if [[ "$3" == "last" ]]; then + # Prevent final line from printing trailing newline + scr_size=( $(stty size 2>/dev/null || echo 24 80) ) + scr_width="${scr_size[1]}" + + title_len="${#1}" + spc_num=$(( (scr_width - title_len) - txt_len )) + [[ "$spc_num" -lt 0 ]] && spc_num="0" + spc=$(printf "%${spc_num}s") + + printf "%s%s$spc" "$1" "$2" + else + # Determine number of spaces for padding + spc_num=$(( 20 - txt_len )) + [[ "$spc_num" -lt 0 ]] && spc_num="0" + spc=$(printf "%${spc_num}s") + + # Print string (Max 20 characters, prevents overflow) + printf "%s%s$spc" "$1" "${2:0:20}" + fi } -get_summary_data() { - local summary=$(GetFTLData "stats") - domains_being_blocked_raw=$(grep "domains_being_blocked" <<< "${summary}" | grep -Eo "[0-9]+$") - domains_being_blocked=$(printf "%'.f" ${domains_being_blocked_raw}) - dns_queries_today_raw=$(grep "dns_queries_today" <<< "$summary" | grep -Eo "[0-9]+$") - dns_queries_today=$(printf "%'.f" ${dns_queries_today_raw}) - ads_blocked_today_raw=$(grep "ads_blocked_today" <<< "$summary" | grep -Eo "[0-9]+$") - ads_blocked_today=$(printf "%'.f" ${ads_blocked_today_raw}) - ads_percentage_today_raw=$(grep "ads_percentage_today" <<< "$summary" | grep -Eo "[0-9.]+$") - LC_NUMERIC=C ads_percentage_today=$(printf "%'.f" ${ads_percentage_today_raw}) +# Perform on first Chrono run (not for JSON formatted string) +get_init_stats() { + LC_NUMERIC=C + calcFunc(){ awk "BEGIN {print $*}"; } + + # Convert bytes to human-readable format + hrBytes() { + awk '{ + num=$1; + if(num==0) { + print "0 B" + } else { + xxx=(num<0?-num:num) + sss=(num<0?-1:1) + split("B KB MB GB TB PB",type) + for(i=5;yyy < 1;i--) { + yyy=xxx / (2^(10*i)) + } + printf "%.0f " type[i+2], yyy*sss + } + }' <<< "$1"; + } + + # Convert seconds to human-readable format + hrSecs() { + day=$(( $1/60/60/24 )); hrs=$(( $1/3600%24 )); mins=$(( ($1%3600)/60 )); secs=$(( $1%60 )) + [[ "$day" -ge "2" ]] && plu="s" + [[ "$day" -ge "1" ]] && days="$day day${plu}, " || days="" + printf "%s%02d:%02d:%02d\n" "$days" "$hrs" "$mins" "$secs" + } + + # Set Colour Codes + coltable="/opt/pihole/COL_TABLE" + if [[ -f "${coltable}" ]]; then + source ${coltable} + else + COL_NC='' + COL_DARK_GRAY='' + COL_LIGHT_GREEN='' + COL_LIGHT_BLUE='' + COL_LIGHT_RED='' + COL_YELLOW='' + COL_LIGHT_RED='' + COL_URG_RED='' + fi + + # Get RPi model number, or OS distro info + if command -v vcgencmd &> /dev/null; then + sys_rev=$(awk '/Revision/ {print $3}' < /proc/cpuinfo) + case "$sys_rev" in + 000[2-6]) sys_model=" 1, Model B";; # 256MB + 000[7-9]) sys_model=" 1, Model A" ;; # 256MB + 000d|000e|000f) sys_model=" 1, Model B";; # 512MB + 0010|0013) sys_model=" 1, Model B+";; # 512MB + 0012|0015) sys_model=" 1, Model A+";; # 256MB + a0104[0-1]|a21041|a22042) sys_model=" 2, Model B";; # 1GB + 900021) sys_model=" 1, Model A+";; # 512MB + 900032) sys_model=" 1, Model B+";; # 512MB + 90009[2-3]|920093) sys_model=" Zero";; # 512MB + 9000c1) sys_model=" Zero W";; # 512MB + a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB + *) sys_model="" ;; + esac + sys_type="Raspberry Pi$sys_model" + else + source "/etc/os-release" + CODENAME=$(sed 's/[()]//g' <<< "${VERSION/* /}") + sys_type="${NAME/ */} ${CODENAME^} $VERSION_ID" + fi + + # Get core count + sys_cores=$(grep -c "^processor" /proc/cpuinfo) + [[ "$sys_cores" -ne 1 ]] && sys_cores_plu="cores" || sys_cores_plu="core" + + # Test existence of clock speed file for ARM CPU + if [[ -f "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]]; then + scaling_freq_file="/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" + fi + + # Test existence of temperature file + if [[ -f "/sys/class/thermal/thermal_zone0/temp" ]]; then + temp_file="/sys/class/thermal/thermal_zone0/temp" + elif [[ -f "/sys/class/hwmon/hwmon0/temp1_input" ]]; then + temp_file="/sys/class/hwmon/hwmon0/temp1_input" + else + temp_file="" + fi + + # Test existence of setupVars config + if [[ -f "/etc/pihole/setupVars.conf" ]]; then + setupVars="/etc/pihole/setupVars.conf" + fi } -normalChrono() { - for (( ; ; )); do - get_summary_data - domain=$(GetFTLData recentBlocked) - clear - # Displays a colorful Pi-hole logo - echo " ___ _ _ _" - echo "| _ (_)___| |_ ___| |___" - echo "| _/ |___| ' \/ _ \ / -_)" - echo "|_| |_| |_||_\___/_\___|" - echo "" - echo " ${IPV4_ADDRESS}" - echo "" - uptime | cut -d' ' -f11- - #uptime -p #Doesn't work on all versions of uptime - uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}' - echo "-------------------------------" - echo "Recently blocked:" - echo " $domain" +get_sys_stats() { + local ph_ver_raw + local cpu_raw + local ram_raw + local disk_raw - echo "Blocking: ${domains_being_blocked}" - echo "Queries: ${dns_queries_today}" - echo "Pi-holed: ${ads_blocked_today} (${ads_percentage_today}%)" - - sleep 5 - done + # Update every 12 refreshes (Def: every 60s) + count=$((count+1)) + if [[ "$count" == "1" ]] || (( "$count" % 12 == 0 )); then + [[ -n "$setupVars" ]] && source "$setupVars" + + + ph_ver_raw=($(pihole -v -c 2> /dev/null | sed -n 's/^.* v/v/p')) + if [[ -n "${ph_ver_raw[0]}" ]]; then + ph_core_ver="${ph_ver_raw[0]}" + ph_lte_ver="${ph_ver_raw[1]}" + ph_ftl_ver="${ph_ver_raw[2]}" + else + ph_core_ver="${COL_LIGHT_RED}API unavailable${COL_NC}" + fi + + sys_name=$(hostname) + + [[ -n "$TEMPERATUREUNIT" ]] && temp_unit="$TEMPERATUREUNIT" || temp_unit="c" + + # Get storage stats for partition mounted on / + disk_raw=($(df -B1 / 2> /dev/null | awk 'END{ print $3,$2,$5 }')) + disk_used="${disk_raw[0]}" + disk_total="${disk_raw[1]}" + disk_perc="${disk_raw[2]}" + + net_gateway=$(route -n | awk '$4 == "UG" {print $2;exit}') + + # Get DHCP stats, if feature is enabled + if [[ "$DHCP_ACTIVE" == "true" ]]; then + ph_dhcp_eip="${DHCP_END##*.}" + ph_dhcp_max=$(( ${DHCP_END##*.} - ${DHCP_START##*.} + 1 )) + fi + + # Get alt DNS server, or print total count of alt DNS servers + if [[ -z "${PIHOLE_DNS_3}" ]]; then + ph_alts="${PIHOLE_DNS_2}" + else + dns_count="0" + [[ -n "${PIHOLE_DNS_2}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_3}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_4}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_5}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_6}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_7}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_8}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_9}" ]] && dns_count="$dns_count+" + ph_alts="${dns_count} others" + fi + fi + + sys_uptime=$(hrSecs "$(cut -d. -f1 /proc/uptime)") + sys_loadavg=$(cut -d " " -f1,2,3 /proc/loadavg) + + # Get CPU usage, only counting processes over 1% CPU as active + cpu_raw=$(ps -eo pcpu,rss --no-headers | grep -E -v " 0") + cpu_tasks=$(wc -l <<< "$cpu_raw") + cpu_taskact=$(sed -r "/(^ 0.)/d" <<< "$cpu_raw" | wc -l) + cpu_perc=$(awk '{sum+=$1} END {printf "%.0f\n", sum/'"$sys_cores"'}' <<< "$cpu_raw") + + # Get CPU clock speed + if [[ -n "$scaling_freq_file" ]]; then + cpu_mhz=$(( $(< /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 )) + else + cpu_mhz=$(lscpu | awk -F "[ .]+" '/MHz/ {print $4;exit}') + fi + + # Determine correct string format for CPU clock speed + if [[ -n "$cpu_mhz" ]]; then + [[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(calcFunc "$cpu_mhz"/1000) Ghz" + [[ -n "$cpu_freq" ]] && cpu_freq_str=" @ $cpu_freq" || cpu_freq_str="" + fi + + # Determine colour for temperature + if [[ -n "$temp_file" ]]; then + if [[ "$temp_unit" == "C" ]]; then + cpu_temp=$(printf "%'.0fc\n" "$(calcFunc "$(< $temp_file) / 1000")") + + case "${cpu_temp::-1}" in + -*|[0-9]|[1-3][0-9]) cpu_col="$COL_LIGHT_BLUE";; + 4[0-9]) cpu_col="";; + 5[0-9]) cpu_col="$COL_YELLOW";; + 6[0-9]) cpu_col="$COL_LIGHT_RED";; + *) cpu_col="$COL_URG_RED";; + esac + + # $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED + cpu_temp_str=", $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY" + + elif [[ "$temp_unit" == "F" ]]; then + cpu_temp=$(printf "%'.0ff\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")") + + case "${cpu_temp::-1}" in + -*|[0-9]|[0-9][0-9]) cpu_col="$COL_LIGHT_BLUE";; + 1[0-1][0-9]) cpu_col="";; + 1[2-3][0-9]) cpu_col="$COL_YELLOW";; + 1[4-5][0-9]) cpu_col="$COL_LIGHT_RED";; + *) cpu_col="$COL_URG_RED";; + esac + + cpu_temp_str=", $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY" + + else + cpu_temp_str=$(printf ", %'.0fk\n" "$(calcFunc "($(< $temp_file) / 1000) + 273.15")") + fi + else + cpu_temp_str="" + fi + + ram_raw=($(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.0f %.0f %.0f", (total-free-buffers-cached)*100/total, (total-free-buffers-cached)*1024, total*1024}' /proc/meminfo)) + ram_perc="${ram_raw[0]}" + ram_used="${ram_raw[1]}" + ram_total="${ram_raw[2]}" + + if [[ "$(pihole status web 2> /dev/null)" == "1" ]]; then + ph_status="${COL_LIGHT_GREEN}Active" + else + ph_status="${COL_LIGHT_RED}Inactive" + fi + + if [[ "$DHCP_ACTIVE" == "true" ]]; then + ph_dhcp_num=$(wc -l 2> /dev/null < "/etc/pihole/dhcp.leases") + fi } -displayHelp() { - cat << EOM -::: Displays stats about your piHole! -::: -::: Usage: sudo pihole -c [optional:-j] -::: Note: If no option is passed, then stats are displayed on screen, updated every 5 seconds -::: -::: Options: -::: -j, --json output stats as JSON formatted string -::: -h, --help display this help text -EOM - exit 0 +get_ftl_stats() { + local stats_raw + + stats_raw=($(pihole-FTL "stats")) + domains_being_blocked_raw="${stats_raw[1]}" + dns_queries_today_raw="${stats_raw[3]}" + ads_blocked_today_raw="${stats_raw[5]}" + ads_percentage_today_raw="${stats_raw[7]}" + + # Only retrieve these stats when not called from jsonFunc + if [[ -z "$1" ]]; then + local recent_blocked_raw + local top_ad_raw + local top_domain_raw + local top_client_raw + + domains_being_blocked=$(printf "%'.0f\n" "${domains_being_blocked_raw}") + dns_queries_today=$(printf "%'.0f\n" "${dns_queries_today_raw}") + ads_blocked_today=$(printf "%'.0f\n" "${ads_blocked_today_raw}") + ads_percentage_today=$(printf "%'.0f\n" "${ads_percentage_today_raw}") + + recent_blocked_raw=$(pihole-FTL recentBlocked) + top_ad_raw=($(pihole-FTL "top-ads (1)")) + top_domain_raw=($(pihole-FTL "top-domains (1)")) + top_client_raw=($(pihole-FTL "top-clients (1)")) + + # Limit strings to 40 characters to prevent overflow + recent_blocked="${recent_blocked_raw:0:40}" + top_ad="${top_ad_raw[2]:0:40}" + top_domain="${top_domain_raw[2]:0:40}" + [[ "${top_client_raw[3]}" ]] && top_client="${top_client_raw[3]:0:40}" || top_client="${top_client_raw[2]:0:40}" + fi +} + +chronoFunc() { + get_init_stats + + for (( ; ; )); do + get_sys_stats + get_ftl_stats + + # Do not print LTE/FTL strings if API is unavailable + ph_core_str=" ${COL_DARK_GRAY}Pi-hole: $ph_core_ver${COL_NC}" + if [[ -n "$ph_lte_ver" ]]; then + ph_lte_str=" ${COL_DARK_GRAY}AdminLTE: $ph_lte_ver${COL_NC}" + ph_ftl_str=" ${COL_DARK_GRAY}FTL: $ph_ftl_ver${COL_NC}" + fi + + clear + + echo -e "|¯¯¯(¯)__|¯|_ ___|¯|___$ph_core_str +| ¯_/¯|__| ' \/ _ \ / -_)$ph_lte_str +|_| |_| |_||_\___/_\___|$ph_ftl_str + ${COL_DARK_GRAY}——————————————————————————————————————————————————————————${COL_NC}" + + printFunc " Hostname: " "$sys_name" + [ -n "$sys_type" ] && printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$sys_type" "$COL_NC" || printf "\n" + + printf "%s\n" " Uptime: $sys_uptime" + + printFunc " Task Load: " "$sys_loadavg" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Active: $cpu_taskact of $cpu_tasks tasks" "$COL_NC" + + printFunc " CPU usage: " "$cpu_perc%" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$sys_cores $sys_cores_plu$cpu_freq_str$cpu_temp_str" "$COL_NC" + + printFunc " RAM usage: " "$ram_perc%" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Used: $(hrBytes "$ram_used") of $(hrBytes "$ram_total")" "$COL_NC" + + printFunc " HDD usage: " "$disk_perc" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Used: $(hrBytes "$disk_used") of $(hrBytes "$disk_total")" "$COL_NC" + + printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Gateway: $net_gateway" "$COL_NC" + + if [[ "$DHCP_ACTIVE" == "true" ]]; then + printFunc " DHCP: " "$DHCP_START to $ph_dhcp_eip" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Leased: $ph_dhcp_num of $ph_dhcp_max" "$COL_NC" + fi + + printFunc " Pi-hole: " "$ph_status" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Blocking: $domains_being_blocked sites" "$COL_NC" + + printFunc " Ads Today: " "$ads_percentage_today%" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$ads_blocked_today of $dns_queries_today queries" "$COL_NC" + + printFunc " Fwd DNS: " "$PIHOLE_DNS_1" + printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Alt DNS: $ph_alts" "$COL_NC" + + echo -e " ${COL_DARK_GRAY}——————————————————————————————————————————————————————————${COL_NC}" + echo " Recently blocked: $recent_blocked" + echo " Top Advertiser: $top_ad" + echo " Top Domain: $top_domain" + printFunc " Top Client: " "$top_client" "last" + + if [[ "$1" == "exit" ]]; then + exit 0 + else + if [[ -n "$1" ]]; then + sleep "${1}" + else + sleep 5 + fi + fi + + done +} + +jsonFunc() { + get_ftl_stats "json" + echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}" +} + +helpFunc() { + if [[ "$1" == "?" ]]; then + echo "Unknown option. Please view 'pihole -c --help' for more information" + else + echo "Usage: pihole -c [options] +Example: 'pihole -c -j' +Calculates stats and displays to an LCD + +Options: + -j, --json Output stats as JSON formatted string + -r, --refresh Set update frequency (in seconds) + -e, --exit Output stats and exit witout refreshing + -h, --help Display this help text" + fi + + exit 0 } if [[ $# = 0 ]]; then - normalChrono + chronoFunc fi for var in "$@"; do - case "$var" in - "-j" | "--json" ) outputJSON;; - "-h" | "--help" ) displayHelp;; - * ) exit 1;; - esac + case "$var" in + "-j" | "--json" ) jsonFunc;; + "-h" | "--help" ) helpFunc;; + "-r" | "--refresh" ) chronoFunc "$2";; + "-e" | "--exit" ) chronoFunc "exit";; + * ) helpFunc "?";; + esac done diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh index 537ebac3..308e1f5e 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -3,14 +3,12 @@ # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. # -# Whitelists and blacklists domains +# Whitelist and blacklist domains # # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. - - -#globals +# Globals basename=pihole piholeDir=/etc/${basename} whitelist=${piholeDir}/whitelist.txt @@ -27,122 +25,118 @@ listMain="" listAlt="" helpFunc() { + if [[ "${listMain}" == "${whitelist}" ]]; then + param="w" + type="white" + elif [[ "${listMain}" == "${wildcardlist}" ]]; then + param="wild" + type="wildcard black" + else + param="b" + type="black" + fi - if [[ ${listMain} == ${whitelist} ]]; then - letter="w" - word="white" - else - letter="b" - word="black" - fi + echo "Usage: pihole -${param} [options] +Example: 'pihole -${param} site.com', or 'pihole -${param} site1.com site2.com' +${type^}list one or more domains - cat << EOM -::: Immediately ${word}lists one or more domains in the hosts file -::: -::: Usage: pihole -${letter} domain1 [domain2 ...] -::: -::: Options: -::: -d, --delmode Remove domains from the ${word}list -::: -nr, --noreload Update ${word}list without refreshing dnsmasq -::: -q, --quiet Output is less verbose -::: -h, --help Show this help dialog -::: -l, --list Display your ${word}listed domains -EOM -if [[ "${letter}" == "b" ]]; then - echo "::: -wild, --wildcard Add wildcard entry (only blacklist)" -fi - exit 0 +Options: + -d, --delmode Remove domain(s) from the ${type}list + -nr, --noreload Update ${type}list without refreshing dnsmasq + -q, --quiet Make output less verbose + -h, --help Show this help dialog + -l, --list Display all your ${type}listed domains" + + exit 0 } EscapeRegexp() { - # This way we may safely insert an arbitrary - # string in our regular expressions - # Also remove leading "." if present - echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g" + # This way we may safely insert an arbitrary + # string in our regular expressions + # Also remove leading "." if present + echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g" } -HandleOther(){ - # First, convert everything to lowercase - domain=$(sed -e "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" <<< "$1") +HandleOther() { + # First, convert everything to lowercase + domain=$(sed -e "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" <<< "$1") - #check validity of domain - validDomain=$(echo "${domain}" | perl -lne 'print if /(?!.*[^a-z0-9-\.].*)^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9-]+\.)*[a-z]{2,63}/') - if [ -z "${validDomain}" ]; then - echo "::: $1 is not a valid argument or domain name" - else - domList=("${domList[@]}" ${validDomain}) - fi + # Check validity of domain + validDomain=$(echo "${domain}" | perl -lne 'print if /(?!.*[^a-z0-9-\.].*)^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9-]+\.)*[a-z]{2,63}/') + if [[ -z "${validDomain}" ]]; then + echo "::: $1 is not a valid argument or domain name" + else + domList=("${domList[@]}" ${validDomain}) + fi } PoplistFile() { - #check whitelist file exists, and if not, create it - if [[ ! -f ${whitelist} ]]; then - touch ${whitelist} - fi - for dom in "${domList[@]}"; do - # Logic : If addmode then add to desired list and remove from the other; if delmode then remove from desired list but do not add to the other - if ${addmode}; then - AddDomain "${dom}" "${listMain}" - RemoveDomain "${dom}" "${listAlt}" - if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then - RemoveDomain "${dom}" "${wildcardlist}" - fi - else - RemoveDomain "${dom}" "${listMain}" - fi - done + # Check whitelist file exists, and if not, create it + if [[ ! -f ${whitelist} ]]; then + touch ${whitelist} + fi + + for dom in "${domList[@]}"; do + # Logic: If addmode then add to desired list and remove from the other; if delmode then remove from desired list but do not add to the other + if ${addmode}; then + AddDomain "${dom}" "${listMain}" + RemoveDomain "${dom}" "${listAlt}" + if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then + RemoveDomain "${dom}" "${wildcardlist}" + fi + else + RemoveDomain "${dom}" "${listMain}" + fi + done } AddDomain() { - list="$2" - domain=$(EscapeRegexp "$1") + list="$2" + domain=$(EscapeRegexp "$1") - if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then + if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then + bool=true + # Is the domain in the list we want to add it to? + grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false - bool=true - #Is the domain in the list we want to add it to? - grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false + if [[ "${bool}" == false ]]; then + # Domain not found in the whitelist file, add it! + if [[ "${verbose}" == true ]]; then + echo "::: Adding $1 to $list..." + fi + reload=true + # Add it to the list we want to add it to + echo "$1" >> "${list}" + else + if [[ "${verbose}" == true ]]; then + echo "::: ${1} already exists in ${list}, no need to add!" + fi + fi + elif [[ "${list}" == "${wildcardlist}" ]]; then + source "${piholeDir}/setupVars.conf" + # Remove the /* from the end of the IPv4addr. + IPV4_ADDRESS=${IPV4_ADDRESS%/*} + IPV6_ADDRESS=${IPV6_ADDRESS} - if [[ "${bool}" == false ]]; then - #domain not found in the whitelist file, add it! - if [[ "${verbose}" == true ]]; then - echo "::: Adding $1 to $list..." - fi - reload=true - # Add it to the list we want to add it to - echo "$1" >> "${list}" - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} already exists in ${list}, no need to add!" - fi - fi + bool=true + # Is the domain in the list? + grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false - elif [[ "${list}" == "${wildcardlist}" ]]; then - - source "${piholeDir}/setupVars.conf" - #Remove the /* from the end of the IPv4addr. - IPV4_ADDRESS=${IPV4_ADDRESS%/*} - IPV6_ADDRESS=${IPV6_ADDRESS} - - bool=true - #Is the domain in the list? - grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false - - if [[ "${bool}" == false ]]; then - if [[ "${verbose}" == true ]]; then - echo "::: Adding $1 to wildcard blacklist..." - fi - reload=true - echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}" - if [[ ${#IPV6_ADDRESS} > 0 ]] ; then - echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}" - fi - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} already exists in wildcard blacklist, no need to add!" - fi - fi - fi + if [[ "${bool}" == false ]]; then + if [[ "${verbose}" == true ]]; then + echo "::: Adding $1 to wildcard blacklist..." + fi + reload=true + echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}" + if [[ "${#IPV6_ADDRESS}" > 0 ]]; then + echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}" + fi + else + if [[ "${verbose}" == true ]]; then + echo "::: ${1} already exists in wildcard blacklist, no need to add!" + fi + fi + fi } RemoveDomain() { @@ -150,85 +144,82 @@ RemoveDomain() { domain=$(EscapeRegexp "$1") if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then - - bool=true - #Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa - grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false - if [[ "${bool}" == true ]]; then - # Remove it from the other one - echo "::: Removing $1 from $list..." - # /I flag: search case-insensitive - sed -i "/${domain}/Id" "${list}" - reload=true - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} does not exist in ${list}, no need to remove!" - fi + bool=true + # Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa + grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false + if [[ "${bool}" == true ]]; then + # Remove it from the other one + echo "::: Removing $1 from $list..." + # /I flag: search case-insensitive + sed -i "/${domain}/Id" "${list}" + reload=true + else + if [[ "${verbose}" == true ]]; then + echo "::: ${1} does not exist in ${list}, no need to remove!" fi - + fi elif [[ "${list}" == "${wildcardlist}" ]]; then - - bool=true - #Is it in the list? - grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false - if [[ "${bool}" == true ]]; then - # Remove it from the other one - echo "::: Removing $1 from $list..." - # /I flag: search case-insensitive - sed -i "/address=\/${domain}/Id" "${list}" - reload=true - else - if [[ "${verbose}" == true ]]; then - echo "::: ${1} does not exist in ${list}, no need to remove!" - fi + bool=true + # Is it in the list? + grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false + if [[ "${bool}" == true ]]; then + # Remove it from the other one + echo "::: Removing $1 from $list..." + # /I flag: search case-insensitive + sed -i "/address=\/${domain}/Id" "${list}" + reload=true + else + if [[ "${verbose}" == true ]]; then + echo "::: ${1} does not exist in ${list}, no need to remove!" fi + fi fi } Reload() { - # Reload hosts file - pihole -g -sd + # Reload hosts file + pihole -g -sd } Displaylist() { - if [[ ${listMain} == ${whitelist} ]]; then - string="gravity resistant domains" - else - string="domains caught in the sinkhole" - fi - verbose=false - echo -e " Displaying $string \n" - count=1 - while IFS= read -r RD; do - echo "${count}: ${RD}" - count=$((count+1)) - done < "${listMain}" - exit 0; + if [[ "${listMain}" == "${whitelist}" ]]; then + string="gravity resistant domains" + else + string="domains caught in the sinkhole" + fi + verbose=false + echo -e "Displaying $string:\n" + count=1 + while IFS= read -r RD; do + echo "${count}: ${RD}" + count=$((count+1)) + done < "${listMain}" + exit 0; } for var in "$@"; do - case "${var}" in - "-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";; - "-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";; - "-wild" | "wildcard" ) listMain="${wildcardlist}";; - "-nr"| "--noreload" ) reload=false;; - "-d" | "--delmode" ) addmode=false;; - "-f" | "--force" ) force=true;; - "-q" | "--quiet" ) verbose=false;; - "-h" | "--help" ) helpFunc;; - "-l" | "--list" ) Displaylist;; - * ) HandleOther "${var}";; - esac + case "${var}" in + "-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";; + "-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";; + "-wild" | "wildcard" ) listMain="${wildcardlist}";; + "-nr"| "--noreload" ) reload=false;; + "-d" | "--delmode" ) addmode=false;; + "-f" | "--force" ) force=true;; + "-q" | "--quiet" ) verbose=false;; + "-h" | "--help" ) helpFunc;; + "-l" | "--list" ) Displaylist;; + * ) HandleOther "${var}";; + esac done shift if [[ $# = 0 ]]; then - helpFunc + helpFunc fi PoplistFile if ${reload}; then - Reload + Reload fi diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh index 09f20d6b..e2c0ab11 100644 --- a/advanced/Scripts/piholeCheckout.sh +++ b/advanced/Scripts/piholeCheckout.sh @@ -3,7 +3,7 @@ # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. # -# Checkout other branches than master +# Switch Pi-hole subsystems to a different Github branch # # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. @@ -18,9 +18,12 @@ PH_TEST="true" source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" # setupVars set in basic-install.sh source "${setupVars}" - update="false" +# Colour codes +red="\e[1;31m" +def="\e[0m" + fully_fetch_repo() { # Add upstream branches to shallow clone local directory="${1}" @@ -35,7 +38,7 @@ fully_fetch_repo() { return 0 } -get_available_branches(){ +get_available_branches() { # Return available branches local directory="${1}" @@ -54,6 +57,8 @@ fetch_checkout_pull_branch() { # Set the reference for the requested branch, fetch, check it put and pull it cd "${directory}" git remote set-branches origin "${branch}" || return 1 + git stash --all --quiet &> /dev/null || true + git clean --force -d || true git fetch --quiet || return 1 checkout_pull_branch "${directory}" "${branch}" || return 1 } @@ -79,23 +84,23 @@ checkout_pull_branch() { } warning1() { - echo "::: Note that changing the branch is a severe change of your Pi-hole system." - echo "::: This is not supported unless one of the developers explicitly asks you to do this!" - read -r -p "::: Have you read and understood this? [y/N] " response + echo " Please note that changing branches severely alters your Pi-hole subsystems" + echo " Features that work on the master branch, may not on a development branch" + echo -e " ${red}This feature is NOT supported unless a Pi-hole developer explicitly asks!${def}" + read -r -p " Have you read and understood this? [y/N] " response case ${response} in [yY][eE][sS]|[yY]) - echo "::: Continuing." + echo "::: Continuing with branch change." return 0 ;; *) - echo "::: Aborting." + echo "::: Branch change has been cancelled." return 1 ;; esac } -checkout() -{ +checkout() { local corebranches local webbranches @@ -192,11 +197,10 @@ checkout() if [[ ! "${1}" == "web" && "${update}" == "true" ]]; then echo "::: Running installer to upgrade your installation" if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then - exit 0 + exit 0 else - echo "Unable to complete update, contact Pi-hole" - exit 1 + echo "Unable to complete update, contact Pi-hole" + exit 1 fi fi } - diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 10dd1e8b..8020cc80 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -260,18 +260,18 @@ ip_ping_check() { if [[ -n ${ip_def_gateway} ]]; then echo -n "::: Pinging default IPv${protocol} gateway: " if ! ping_gateway="$(${cmd} -q -W 3 -c 3 -n ${ip_def_gateway} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then - echo "Gateway did not respond." + log_echo "Gateway did not respond." return 1 else - echo "Gateway responded." + log_echo "Gateway responded." log_write "${ping_gateway}" fi echo -n "::: Pinging Internet via IPv${protocol}: " if ! ping_inet="$(${cmd} -q -W 3 -c 3 -n ${g_addr} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then - echo "Query did not respond." + log_echo "Query did not respond." return 1 else - echo "Query responded." + log_echo "Query responded." log_write "${ping_inet}" fi else diff --git a/advanced/Scripts/piholeLogFlush.sh b/advanced/Scripts/piholeLogFlush.sh index fd66b255..cc553b32 100755 --- a/advanced/Scripts/piholeLogFlush.sh +++ b/advanced/Scripts/piholeLogFlush.sh @@ -8,17 +8,38 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. -echo -n "::: Flushing /var/log/pihole.log ..." -# Test if logrotate is available on this system -if command -v /usr/sbin/logrotate &> /dev/null; then - # Flush twice to move all data out of sight of FTL - /usr/sbin/logrotate --force /etc/pihole/logrotate - /usr/sbin/logrotate --force /etc/pihole/logrotate +if [[ "$@" != *"quiet"* ]]; then + echo -n "::: Flushing /var/log/pihole.log ..." +fi +if [[ "$@" == *"once"* ]]; then + # Nightly logrotation + if command -v /usr/sbin/logrotate >/dev/null; then + # Logrotate once + /usr/sbin/logrotate --force /etc/pihole/logrotate + else + # Copy pihole.log over to pihole.log.1 + # and empty out pihole.log + # Note that moving the file is not an option, as + # dnsmasq would happily continue writing into the + # moved file (it will have the same file handler) + cp /var/log/pihole.log /var/log/pihole.log.1 + echo " " > /var/log/pihole.log + fi else - # Flush both pihole.log and pihole.log.1 (if existing) - echo " " > /var/log/pihole.log - if [ -f /var/log/pihole.log.1 ]; then - echo " " > /var/log/pihole.log.1 + # Manual flushing + if command -v /usr/sbin/logrotate >/dev/null; then + # Logrotate twice to move all data out of sight of FTL + /usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3 + /usr/sbin/logrotate --force /etc/pihole/logrotate + else + # Flush both pihole.log and pihole.log.1 (if existing) + echo " " > /var/log/pihole.log + if [ -f /var/log/pihole.log.1 ]; then + echo " " > /var/log/pihole.log.1 + fi fi fi -echo "... done!" + +if [[ "$@" != *"quiet"* ]]; then + echo "... done!" +fi diff --git a/advanced/Scripts/update.sh b/advanced/Scripts/update.sh index 4fceb931..6aef183b 100755 --- a/advanced/Scripts/update.sh +++ b/advanced/Scripts/update.sh @@ -117,7 +117,10 @@ main() { echo "::: FTL: up to date" fi - if ${FTL_update}; then + # Logic: Don't update FTL when there is a core update available + # since the core update will run the installer which will itself + # re-install (i.e. update) FTL + if ${FTL_update} && ! ${core_update}; then echo ":::" echo "::: FTL out of date" FTLdetect @@ -194,21 +197,21 @@ main() { if [[ "${web_update}" == true ]]; then web_version_current="$(/usr/local/bin/pihole version --admin --current)" echo ":::" - echo "::: Web Admin version is now at ${web_version_current}" + echo "::: Web Admin version is now at ${web_version_current/* v/v}}" echo "::: If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'" fi if [[ "${core_update}" == true ]]; then pihole_version_current="$(/usr/local/bin/pihole version --pihole --current)" echo ":::" - echo "::: Pi-hole version is now at ${pihole_version_current}" + echo "::: Pi-hole version is now at ${pihole_version_current/* v/v}}" echo "::: If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'" fi if [[ ${FTL_update} == true ]]; then - FTL_version_current="$(/usr/bin/pihole-FTL tag)" + FTL_version_current="$(/usr/local/bin/pihole version --ftl --current)" echo ":::" - echo "::: FTL version is now at ${FTL_version_current}" + echo "::: FTL version is now at ${FTL_version_current/* v/v}}" start_service pihole-FTL enable_service pihole-FTL fi diff --git a/advanced/Scripts/version.sh b/advanced/Scripts/version.sh index 7f96e29a..f5e0f51d 100755 --- a/advanced/Scripts/version.sh +++ b/advanced/Scripts/version.sh @@ -3,24 +3,29 @@ # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. # -# shows version numbers +# Show version numbers # # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. # Variables DEFAULT="-1" -PHGITDIR="/etc/.pihole/" +COREGITDIR="/etc/.pihole/" WEBGITDIR="/var/www/html/admin/" getLocalVersion() { + # FTL requires a different method + if [[ "$1" == "FTL" ]]; then + pihole-FTL version + return 0 + fi + # Get the tagged version of the local repository local directory="${1}" local version - cd "${directory}" || { echo "${DEFAULT}"; return 1; } - version=$(git describe --tags --always || \ - echo "${DEFAULT}") + cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; } + version=$(git describe --tags --always || echo "$DEFAULT") if [[ "${version}" =~ ^v ]]; then echo "${version}" elif [[ "${version}" == "${DEFAULT}" ]]; then @@ -33,13 +38,18 @@ getLocalVersion() { } getLocalHash() { + # Local FTL hash does not exist on filesystem + if [[ "$1" == "FTL" ]]; then + echo "N/A" + return 0 + fi + # Get the short hash of the local repository local directory="${1}" local hash - cd "${directory}" || { echo "${DEFAULT}"; return 1; } - hash=$(git rev-parse --short HEAD || \ - echo "${DEFAULT}") + cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; } + hash=$(git rev-parse --short HEAD || echo "$DEFAULT") if [[ "${hash}" == "${DEFAULT}" ]]; then echo "ERROR" return 1 @@ -49,12 +59,33 @@ getLocalHash() { return 0 } +getRemoteHash(){ + # Remote FTL hash is not applicable + if [[ "$1" == "FTL" ]]; then + echo "N/A" + return 0 + fi + + local daemon="${1}" + local branch="${2}" + + hash=$(git ls-remote --heads "https://github.com/pi-hole/${daemon}" | \ + awk -v bra="$branch" '$0~bra {print substr($0,0,8);exit}') + if [[ -n "$hash" ]]; then + echo "$hash" + else + echo "ERROR" + return 1 + fi + return 0 +} + getRemoteVersion(){ # Get the version from the remote origin local daemon="${1}" local version - version=$(curl --silent --fail https://api.github.com/repos/pi-hole/${daemon}/releases/latest | \ + version=$(curl --silent --fail "https://api.github.com/repos/pi-hole/${daemon}/releases/latest" | \ awk -F: '$1 ~/tag_name/ { print $2 }' | \ tr -cd '[[:alnum:]]._-') if [[ "${version}" =~ ^v ]]; then @@ -66,72 +97,72 @@ getRemoteVersion(){ return 0 } -#PHHASHLATEST=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/commits/master | \ -# grep sha | \ -# head -n1 | \ -# awk -F ' ' '{ print $2 }' | \ -# tr -cd '[[:alnum:]]._-') - -#WEBHASHLATEST=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/commits/master | \ -# grep sha | \ -# head -n1 | \ -# awk -F ' ' '{ print $2 }' | \ -# tr -cd '[[:alnum:]]._-') - - -normalOutput() { - echo "::: Pi-hole version is $(getLocalVersion "${PHGITDIR}") (Latest version is $(getRemoteVersion pi-hole))" - if [ -d "${WEBGITDIR}" ]; then - echo "::: Web-Admin version is $(getLocalVersion "${WEBGITDIR}") (Latest version is $(getRemoteVersion AdminLTE))" - fi -} - -webOutput() { - if [ -d "${WEBGITDIR}" ]; then - case "${1}" in - "-l" | "--latest" ) echo $(getRemoteVersion AdminLTE);; - "-c" | "--current" ) echo $(getLocalVersion "${WEBGITDIR}");; - "-h" | "--hash" ) echo $(getLocalHash "${WEBGITDIR}");; - * ) echo "::: Invalid Option!"; exit 1; - esac - else - echo "::: Web interface not installed!"; exit 1; +versionOutput() { + [[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR + [[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR + [[ "$1" == "FTL" ]] && GITDIR="FTL" + + [[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $GITDIR) + [[ "$2" == "-l" ]] || [[ "$2" == "--latest" ]] || [[ -z "$2" ]] && latest=$(getRemoteVersion "$1") + if [[ "$2" == "-h" ]] || [[ "$2" == "--hash" ]]; then + [[ "$3" == "-c" ]] || [[ "$3" == "--current" ]] || [[ -z "$3" ]] && curHash=$(getLocalHash "$GITDIR") + [[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)") fi + + if [[ -n "$current" ]] && [[ -n "$latest" ]]; then + output="${1^} version is $current (Latest: $latest)" + elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then + output="Current ${1^} version is $current" + elif [[ -z "$current" ]] && [[ -n "$latest" ]]; then + output="Latest ${1^} version is $latest" + elif [[ "$curHash" == "N/A" ]] || [[ "$latHash" == "N/A" ]]; then + output="${1^} hash is not applicable" + elif [[ -n "$curHash" ]] && [[ -n "$latHash" ]]; then + output="${1^} hash is $curHash (Latest: $latHash)" + elif [[ -n "$curHash" ]] && [[ -z "$latHash" ]]; then + output="Current ${1^} hash is $curHash" + elif [[ -z "$curHash" ]] && [[ -n "$latHash" ]]; then + output="Latest ${1^} hash is $latHash" + else + errorOutput + fi + + [[ -n "$output" ]] && echo " $output" } -coreOutput() { - case "${1}" in - "-l" | "--latest" ) echo $(getRemoteVersion pi-hole);; - "-c" | "--current" ) echo $(getLocalVersion "${PHGITDIR}");; - "-h" | "--hash" ) echo $(getLocalHash "${PHGITDIR}");; - * ) echo "::: Invalid Option!"; exit 1; - esac +errorOutput() { + echo " Invalid Option! Try 'pihole -v --help' for more information." + exit 1 +} + +defaultOutput() { + versionOutput "pi-hole" "$@" + versionOutput "AdminLTE" "$@" + versionOutput "FTL" "$@" } helpFunc() { - cat << EOM -::: -::: Show Pi-hole/Web Admin versions -::: -::: Usage: pihole -v [ -a | -p ] [ -l | -c ] -::: -::: Options: -::: -a, --admin Show both current and latest versions of web admin -::: -p, --pihole Show both current and latest versions of Pi-hole core files -::: -l, --latest (Only after -a | -p) Return only latest version -::: -c, --current (Only after -a | -p) Return only current version -::: -h, --help Show this help dialog -::: -EOM - exit 0 + echo "Usage: pihole -v [repo | option] [option] +Example: 'pihole -v -p -l' +Show Pi-hole, Admin Console & FTL versions + +Repositories: + -p, --pihole Only retrieve info regarding Pi-hole repository + -a, --admin Only retrieve info regarding AdminLTE repository + -f, --ftl Only retrieve info regarding FTL repository + +Options: + -c, --current Return the current version + -l, --latest Return the latest version + --hash Return the Github hash from your local repositories + -h, --help Show this help dialog" + exit 0 } -if [[ $# = 0 ]]; then - normalOutput -fi - case "${1}" in - "-a" | "--admin" ) shift; webOutput "$@";; - "-p" | "--pihole" ) shift; coreOutput "$@" ;; + "-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";; + "-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";; + "-f" | "--ftl" ) shift; versionOutput "FTL" "$@";; "-h" | "--help" ) helpFunc;; + * ) defaultOutput "$@";; esac diff --git a/advanced/Scripts/webpage.sh b/advanced/Scripts/webpage.sh index d3ad3032..8419aa8d 100755 --- a/advanced/Scripts/webpage.sh +++ b/advanced/Scripts/webpage.sh @@ -8,7 +8,6 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. - readonly setupVars="/etc/pihole/setupVars.conf" readonly dnsmasqconfig="/etc/dnsmasq.d/01-pihole.conf" readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf" @@ -16,23 +15,19 @@ readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf" readonly dhcpstaticconfig="/etc/dnsmasq.d/04-pihole-static-dhcp.conf" helpFunc() { - cat << EOM -::: Set admin options for the web interface of pihole -::: -::: Usage: pihole -a [options] -::: -::: Options: -::: -p, password Set web interface password, an empty input will remove any previously set password -::: -c, celsius Set Celsius temperature unit -::: -f, fahrenheit Set Fahrenheit temperature unit -::: -k, kelvin Set Kelvin temperature unit -::: -h, --help Show this help dialog -::: -i, interface Setup interface listening behavior of dnsmasq -::: pihole -a -i local : Listen on all interfaces, but allow only queries from -::: devices that are at most one hop away (local devices) -::: pihole -a -i single : Listen only on one interface (see PIHOLE_INTERFACE) -::: pihole -a -i all : Listen on all interfaces, permit all origins -EOM + echo "Usage: pihole -a [options] +Example: pihole -a -p password +Set options for the Admin Console + +Options: + -f, flush Flush the Pi-hole log + -p, password Set Admin Console password + -c, celsius Set Celsius as preferred temperature unit + -f, fahrenheit Set Fahrenheit as preferred temperature unit + -k, kelvin Set Kelvin as preferred temperature unit + -h, --help Show this help dialog + -i, interface Specify dnsmasq's interface listening behavior + Add '-h' for more info on interface usage" exit 0 } @@ -61,21 +56,18 @@ delete_dnsmasq_setting() { sed -i "/${1}/d" "${dnsmasqconfig}" } -SetTemperatureUnit(){ - +SetTemperatureUnit() { change_setting "TEMPERATUREUNIT" "${unit}" - } -HashPassword(){ - # Compute password hash twice to avoid rainbow table vulnerability - return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//') - return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//') - echo ${return} +HashPassword() { + # Compute password hash twice to avoid rainbow table vulnerability + return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//') + return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//') + echo ${return} } -SetWebPassword(){ - +SetWebPassword() { if [ "${SUDO_USER}" == "www-data" ]; then echo "Security measure: user www-data is not allowed to change webUI password!" echo "Exiting" @@ -175,8 +167,7 @@ trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE3 } -SetDNSServers(){ - +SetDNSServers() { # Save setting to file delete_setting "PIHOLE_DNS" IFS=',' read -r -a array <<< "${args[2]}" @@ -207,72 +198,59 @@ SetDNSServers(){ # Restart dnsmasq to load new configuration RestartDNS - } -SetExcludeDomains(){ - +SetExcludeDomains() { change_setting "API_EXCLUDE_DOMAINS" "${args[2]}" - } -SetExcludeClients(){ - +SetExcludeClients() { change_setting "API_EXCLUDE_CLIENTS" "${args[2]}" - } -Reboot(){ - +Reboot() { nohup bash -c "sleep 5; reboot" &> /dev/null /dev/null else service dnsmasq restart &> /dev/null fi - } -SetQueryLogOptions(){ - +SetQueryLogOptions() { change_setting "API_QUERY_LOG_SHOW" "${args[2]}" - } ProcessDHCPSettings() { - source "${setupVars}" if [[ "${DHCP_ACTIVE}" == "true" ]]; then + interface=$(grep 'PIHOLE_INTERFACE=' /etc/pihole/setupVars.conf | sed "s/.*=//") - interface=$(grep 'PIHOLE_INTERFACE=' /etc/pihole/setupVars.conf | sed "s/.*=//") + # Use eth0 as fallback interface + if [ -z ${interface} ]; then + interface="eth0" + fi - # Use eth0 as fallback interface - if [ -z ${interface} ]; then - interface="eth0" - fi + if [[ "${PIHOLE_DOMAIN}" == "" ]]; then + PIHOLE_DOMAIN="local" + change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}" + fi - if [[ "${PIHOLE_DOMAIN}" == "" ]]; then - PIHOLE_DOMAIN="local" - change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}" - fi + if [[ "${DHCP_LEASETIME}" == "0" ]]; then + leasetime="infinite" + elif [[ "${DHCP_LEASETIME}" == "" ]]; then + leasetime="24h" + change_setting "DHCP_LEASETIME" "${leasetime}" + else + leasetime="${DHCP_LEASETIME}h" + fi - if [[ "${DHCP_LEASETIME}" == "0" ]]; then - leasetime="infinite" - elif [[ "${DHCP_LEASETIME}" == "" ]]; then - leasetime="24h" - change_setting "DHCP_LEASETIME" "${leasetime}" - else - leasetime="${DHCP_LEASETIME}h" - fi - - # Write settings to file - echo "############################################################################### + # Write settings to file + echo "############################################################################### # DHCP SERVER CONFIG FILE AUTOMATICALLY POPULATED BY PI-HOLE WEB INTERFACE. # # ANY CHANGES MADE TO THIS FILE WILL BE LOST ON CHANGE # ############################################################################### @@ -283,26 +261,25 @@ dhcp-leasefile=/etc/pihole/dhcp.leases #quiet-dhcp " > "${dhcpconfig}" -if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then - echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}" -fi + if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then + echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}" + fi - if [[ "${DHCP_IPv6}" == "true" ]]; then -echo "#quiet-dhcp6 + if [[ "${DHCP_IPv6}" == "true" ]]; then + echo "#quiet-dhcp6 #enable-ra dhcp-option=option6:dns-server,[::] dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,${leasetime} ra-param=*,0,0 " >> "${dhcpconfig}" - fi + fi else rm "${dhcpconfig}" &> /dev/null fi } -EnableDHCP(){ - +EnableDHCP() { change_setting "DHCP_ACTIVE" "true" change_setting "DHCP_START" "${args[2]}" change_setting "DHCP_END" "${args[3]}" @@ -320,8 +297,7 @@ EnableDHCP(){ RestartDNS } -DisableDHCP(){ - +DisableDHCP() { change_setting "DHCP_ACTIVE" "false" # Remove possible old setting from file @@ -333,23 +309,20 @@ DisableDHCP(){ RestartDNS } -SetWebUILayout(){ - +SetWebUILayout() { change_setting "WEBUIBOXEDLAYOUT" "${args[2]}" - } CustomizeAdLists() { - list="/etc/pihole/adlists.list" - if [[ "${args[2]}" == "enable" ]] ; then + if [[ "${args[2]}" == "enable" ]]; then sed -i "\\@${args[3]}@s/^#http/http/g" "${list}" - elif [[ "${args[2]}" == "disable" ]] ; then + elif [[ "${args[2]}" == "disable" ]]; then sed -i "\\@${args[3]}@s/^http/#http/g" "${list}" - elif [[ "${args[2]}" == "add" ]] ; then + elif [[ "${args[2]}" == "add" ]]; then echo "${args[3]}" >> ${list} - elif [[ "${args[2]}" == "del" ]] ; then + elif [[ "${args[2]}" == "del" ]]; then var=$(echo "${args[3]}" | sed 's/\//\\\//g') sed -i "/${var}/Id" "${list}" else @@ -358,18 +331,15 @@ CustomizeAdLists() { fi } -SetPrivacyMode(){ - - if [[ "${args[2]}" == "true" ]] ; then +SetPrivacyMode() { + if [[ "${args[2]}" == "true" ]]; then change_setting "API_PRIVACY_MODE" "true" else change_setting "API_PRIVACY_MODE" "false" fi - } ResolutionSettings() { - typ="${args[2]}" state="${args[3]}" @@ -378,11 +348,9 @@ ResolutionSettings() { elif [[ "${typ}" == "clients" ]]; then change_setting "API_GET_CLIENT_HOSTNAME" "${state}" fi - } AddDHCPStaticAddress() { - mac="${args[2]}" ip="${args[3]}" host="${args[4]}" @@ -397,18 +365,14 @@ AddDHCPStaticAddress() { # Full info given echo "dhcp-host=${mac},${ip},${host}" >> "${dhcpstaticconfig}" fi - } RemoveDHCPStaticAddress() { - mac="${args[2]}" sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}" - } -SetHostRecord(){ - +SetHostRecord() { if [ -n "${args[3]}" ]; then change_setting "HOSTRECORD" "${args[2]},${args[3]}" echo "Setting host record for ${args[2]} -> ${args[3]}" @@ -421,17 +385,28 @@ SetHostRecord(){ # Restart dnsmasq to load new configuration RestartDNS - } -SetListeningMode(){ - +SetListeningMode() { source "${setupVars}" + + if [[ "$3" == "-h" ]] || [[ "$3" == "--help" ]]; then + echo "Usage: pihole -a -i [interface] +Example: 'pihole -a -i local' +Specify dnsmasq's network interface listening behavior - if [[ "${args[2]}" == "all" ]] ; then +Interfaces: + local Listen on all interfaces, but only allow queries from + devices that are at most one hop away (local devices) + single Listen only on ${PIHOLE_INTERFACE} interface + all Listen on all interfaces, permit all origins" + exit 0 + fi + + if [[ "${args[2]}" == "all" ]]; then echo "Listening on all interfaces, permiting all origins, hope you have a firewall!" change_setting "DNSMASQ_LISTENING" "all" - elif [[ "${args[2]}" == "local" ]] ; then + elif [[ "${args[2]}" == "local" ]]; then echo "Listening on all interfaces, permitting only origins that are at most one hop away (local devices)" change_setting "DNSMASQ_LISTENING" "local" else @@ -446,17 +421,14 @@ SetListeningMode(){ # Restart dnsmasq to load new configuration RestartDNS fi - } -Teleporter() -{ +Teleporter() { local datetimestamp=$(date "+%Y-%m-%d_%H-%M-%S") php /var/www/html/admin/scripts/pi-hole/php/teleporter.php > "pi-hole-teleporter_${datetimestamp}.zip" } main() { - args=("$@") case "${args[1]}" in @@ -479,7 +451,7 @@ main() { "addstaticdhcp" ) AddDHCPStaticAddress;; "removestaticdhcp" ) RemoveDHCPStaticAddress;; "hostrecord" ) SetHostRecord;; - "-i" | "interface" ) SetListeningMode;; + "-i" | "interface" ) SetListeningMode "$@";; "-t" | "teleporter" ) Teleporter;; "adlist" ) CustomizeAdLists;; * ) helpFunc;; @@ -490,5 +462,4 @@ main() { if [[ $# = 0 ]]; then helpFunc fi - } diff --git a/advanced/index.php b/advanced/index.php index bfc44a1d..1dd5acc7 100644 --- a/advanced/index.php +++ b/advanced/index.php @@ -185,7 +185,7 @@ function add() { } $.ajax({ - url: "admin/scripts/pi-hole/php/add.php", + url: "/admin/scripts/pi-hole/php/add.php", method: "post", data: {"domain":domain.val(), "list":"white", "pw":pw.val()}, success: function(response) { diff --git a/advanced/logrotate b/advanced/logrotate index 570e7548..ffed910b 100644 --- a/advanced/logrotate +++ b/advanced/logrotate @@ -8,3 +8,14 @@ notifempty nomail } + +/var/log/pihole-FTL.log { + # su # + weekly + copytruncate + rotate 3 + compress + delaycompress + notifempty + nomail +} diff --git a/advanced/pihole-FTL.service b/advanced/pihole-FTL.service index 30cd140f..627fad8c 100644 --- a/advanced/pihole-FTL.service +++ b/advanced/pihole-FTL.service @@ -26,7 +26,7 @@ start() { echo "pihole-FTL is already running" else touch /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port - chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port + chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /etc/pihole chmod 0644 /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port su -s /bin/sh -c "/usr/bin/pihole-FTL" "$FTLUSER" echo diff --git a/advanced/pihole.cron b/advanced/pihole.cron index c885b371..f1beb08c 100644 --- a/advanced/pihole.cron +++ b/advanced/pihole.cron @@ -21,9 +21,10 @@ # Pi-hole: Update Pi-hole! Uncomment to enable auto update #30 2 * * 7 root PATH="$PATH:/usr/local/bin/" pihole updatePihole -# Pi-hole: Flush the log daily at 00:00 so it doesn't get out of control -# Stats will be viewable in the Web interface thanks to the cron job above +# Pi-hole: Flush the log daily at 00:00 # The flush script will use logrotate if available -00 00 * * * root PATH="$PATH:/usr/local/bin/" pihole flush +# parameter "once": logrotate only once (default is twice) +# parameter "quiet": don't print messages +00 00 * * * root PATH="$PATH:/usr/local/bin/" pihole flush once quiet @reboot root /usr/sbin/logrotate /etc/pihole/logrotate diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index c65ef49f..053e04ba 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -86,7 +86,7 @@ if command -v apt-get &> /dev/null; then #Debian Family ############################################# PKG_MANAGER="apt-get" - UPDATE_PKG_CACHE="test_dpkg_lock; ${PKG_MANAGER} update" + UPDATE_PKG_CACHE="${PKG_MANAGER} update" PKG_INSTALL=(${PKG_MANAGER} --yes --no-install-recommends install) # grep -c will return 1 retVal on 0 matches, block this throwing the set -e with an OR TRUE PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true" @@ -220,6 +220,16 @@ getGitFiles() { return 0 } +resetRepo() { + local directory="${1}" + + cd "${directory}" &> /dev/null || return 1 + echo -n "::: Resetting repo in ${1}..." + git reset --hard &> /dev/null || return $? + echo " done!" + return 0 +} + find_IPv4_information() { local route # Find IP used to route to outside world @@ -317,16 +327,44 @@ chooseInterface() { fi } +# See https://github.com/pi-hole/pi-hole/issues/1473#issuecomment-301745953 +testIPv6() { + first="$(cut -f1 -d":" <<< "$1")" + value1=$(((0x$first)/256)) + value2=$(((0x$first)%256)) + ((($value1&254)==252)) && echo "ULA" || true + ((($value1&112)==32)) && echo "GUA" || true + ((($value1==254) && (($value2&192)==128))) && echo "Link-local" || true +} + useIPv6dialog() { - # Show the IPv6 address used for blocking - IPV6_ADDRESS=$(ip -6 route get 2001:4860:4860::8888 | grep -v "unreachable" | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "src") print $(i+1) }') + # Determine the IPv6 address used for blocking + IPV6_ADDRESSES=($(ip -6 address | grep 'scope global' | awk '{print $2}')) + + # Determine type of found IPv6 addresses + for i in "${IPV6_ADDRESSES[@]}"; do + result=$(testIPv6 "$i") + [[ "${result}" == "ULA" ]] && ULA_ADDRESS="$i" + [[ "${result}" == "GUA" ]] && GUA_ADDRESS="$i" + done + + # Determine which address to be used: Prefer ULA over GUA or don't use any if none found + if [[ ! -z "${ULA_ADDRESS}" ]]; then + IPV6_ADDRESS="${ULA_ADDRESS}" + echo "::: Found IPv6 ULA address, using it for blocking IPv6 ads" + elif [[ ! -z "${GUA_ADDRESS}" ]]; then + echo "::: Found IPv6 GUA address, using it for blocking IPv6 ads" + IPV6_ADDRESS="${GUA_ADDRESS}" + else + echo "::: Found neither IPv6 ULA nor GUA address, blocking IPv6 ads will not be enabled" + IPV6_ADDRESS="" + fi if [[ ! -z "${IPV6_ADDRESS}" ]]; then whiptail --msgbox --backtitle "IPv6..." --title "IPv6 Supported" "$IPV6_ADDRESS will be used to block ads." ${r} ${c} fi } - use4andor6() { local useIPv4 local useIPv6 @@ -408,7 +446,7 @@ setDHCPCD() { echo "interface ${PIHOLE_INTERFACE} static ip_address=${IPV4_ADDRESS} static routers=${IPv4gw} - static domain_name_servers=${IPv4gw}" | tee -a /etc/dhcpcd.conf >/dev/null + static domain_name_servers=127.0.0.1" | tee -a /etc/dhcpcd.conf >/dev/null } setStaticIPv4() { @@ -980,6 +1018,7 @@ configureFirewall() { iptables -C INPUT -p tcp -m tcp --dport 80 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT iptables -C INPUT -p tcp -m tcp --dport 53 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT iptables -C INPUT -p udp -m udp --dport 53 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT + iptables -C INPUT -p tcp -m tcp --dport 4711:4720 -i lo -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 4711:4720 -i lo -j ACCEPT return 0 fi else @@ -1041,7 +1080,7 @@ installLogrotate() { # the local properties of the /var/log directory logusergroup="$(stat -c '%U %G' /var/log)" if [[ ! -z $logusergroup ]]; then - sed -i "s/# su #/su ${logusergroup}/" /etc/pihole/logrotate + sed -i "s/# su #/su ${logusergroup}/g;" /etc/pihole/logrotate fi echo " done!" } @@ -1128,10 +1167,18 @@ checkSelinux() { displayFinalMessage() { + if [[ ${#1} -gt 0 ]] ; then + pwstring="$1" + elif [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) -gt 0 ]]; then + pwstring="unchanged" + else + pwstring="NOT SET" + fi + if [[ ${INSTALL_WEB} == true ]]; then additional="View the web interface at http://pi.hole/admin or http://${IPV4_ADDRESS%/*}/admin -Your Admin Webpage login password is ${1:-"NOT SET"}" +Your Admin Webpage login password is ${pwstring}" fi # Final completion message to user @@ -1179,22 +1226,32 @@ update_dialogs() { } clone_or_update_repos() { -if [[ "${reconfigure}" == true ]]; then - echo "::: --reconfigure passed to install script. Not downloading/updating local repos" - else - # Get Git files for Core and Admin - getGitFiles ${PI_HOLE_LOCAL_REPO} ${piholeGitUrl} || \ - { echo "!!! Unable to clone ${piholeGitUrl} into ${PI_HOLE_LOCAL_REPO}, unable to continue."; \ + if [[ "${reconfigure}" == true ]]; then + echo "::: --reconfigure passed to install script. Resetting changes to local repos" + resetRepo ${PI_HOLE_LOCAL_REPO} || \ + { echo "!!! Unable to reset ${PI_HOLE_LOCAL_REPO}, unable to continue."; \ + exit 1; \ + } + if [[ ${INSTALL_WEB} == true ]]; then + resetRepo ${webInterfaceDir} || \ + { echo "!!! Unable to reset ${webInterfaceDir}, unable to continue."; \ exit 1; \ } - - if [[ ${INSTALL_WEB} == true ]]; then - getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl} || \ - { echo "!!! Unable to clone ${webInterfaceGitUrl} into ${webInterfaceDir}, unable to continue."; \ - exit 1; \ - } - fi fi + else + # Get Git files for Core and Admin + getGitFiles ${PI_HOLE_LOCAL_REPO} ${piholeGitUrl} || \ + { echo "!!! Unable to clone ${piholeGitUrl} into ${PI_HOLE_LOCAL_REPO}, unable to continue."; \ + exit 1; \ + } + + if [[ ${INSTALL_WEB} == true ]]; then + getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl} || \ + { echo "!!! Unable to clone ${webInterfaceGitUrl} into ${webInterfaceDir}, unable to continue."; \ + exit 1; \ + } + fi + fi } FTLinstall() { @@ -1220,6 +1277,7 @@ FTLinstall() { echo -n "transferred... " stop_service pihole-FTL &> /dev/null install -T -m 0755 /tmp/${binary} /usr/bin/pihole-FTL + rm /tmp/${binary} /tmp/${binary}.sha1 cd "${orig_dir}" install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/pihole-FTL.service" "/etc/init.d/pihole-FTL" echo "done." diff --git a/gravity.sh b/gravity.sh index a5231d5e..285ce5c3 100755 --- a/gravity.sh +++ b/gravity.sh @@ -54,6 +54,7 @@ IPV6_ADDRESS=${IPV6_ADDRESS} basename=pihole piholeDir=/etc/${basename} adList=${piholeDir}/gravity.list +blackList=${piholeDir}/black.list localList=${piholeDir}/local.list justDomainsExtension=domains matterAndLight=${basename}.0.matterandlight.txt @@ -235,9 +236,7 @@ gravity_Blacklist() { if [[ -f "${blacklistFile}" ]]; then numBlacklisted=$(wc -l < "${blacklistFile}") plural=; [[ "$numBlacklisted" != "1" ]] && plural=s - echo -n "::: Blacklisting $numBlacklisted domain${plural}..." - cat ${blacklistFile} >> ${piholeDir}/${eventHorizon} - echo " done!" + echo "::: Exact blocked domain${plural}: $numBlacklisted" else echo "::: Nothing to blacklist!" fi @@ -299,9 +298,25 @@ gravity_unique() { echo "::: $numberOf unique domains trapped in the event horizon." } -gravity_hostFormat() { +gravity_doHostFormat() { + # Check vars from setupVars.conf to see if we're using IPv4, IPv6, Or both. + if [[ -n "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then + # Both IPv4 and IPv6 + awk -v ipv4addr="$IPV4_ADDRESS" -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> "${2}" < "${1}" + elif [[ -n "${IPV4_ADDRESS}" && -z "${IPV6_ADDRESS}" ]];then + # Only IPv4 + awk -v ipv4addr="$IPV4_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0}' >> "${2}" < "${1}" + elif [[ -z "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then + # Only IPv6 + awk -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv6addr" "$0}' >> "${2}" < "${1}" + elif [[ -z "${IPV4_ADDRESS}" && -z "${IPV6_ADDRESS}" ]];then + echo "::: No IP Values found! Please run 'pihole -r' and choose reconfigure to restore values" + exit 1 + fi +} + +gravity_hostFormatLocal() { # Format domain list as "192.168.x.x domain.com" - echo -n "::: Formatting domains into a HOSTS file..." if [[ -f /etc/hostname ]]; then hostname=$( ${localList} - # Both IPv4 and IPv6 - cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPV4_ADDRESS" -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> ${piholeDir}/${accretionDisc} - - elif [[ -n "${IPV4_ADDRESS}" && -z "${IPV6_ADDRESS}" ]];then - - echo -e "${IPV4_ADDRESS} ${hostname}\n${IPV4_ADDRESS} pi.hole" > ${localList} - # Only IPv4 - cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPV4_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0}' >> ${piholeDir}/${accretionDisc} - - elif [[ -z "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then - - echo -e "${IPV6_ADDRESS} ${hostname}\n${IPV6_ADDRESS} pi.hole" > ${localList} - # Only IPv6 - cat ${piholeDir}/${eventHorizon} | awk -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv6addr" "$0}' >> ${piholeDir}/${accretionDisc} - - elif [[ -z "${IPV4_ADDRESS}" && -z "${IPV6_ADDRESS}" ]];then - echo "::: No IP Values found! Please run 'pihole -r' and choose reconfigure to restore values" - exit 1 - fi + echo -e "${hostname}\npi.hole" > "${localList}.tmp" + # Copy the file over as /etc/pihole/local.list so dnsmasq can use it + rm "${localList}" + gravity_doHostFormat "${localList}.tmp" "${localList}" + rm "${localList}.tmp" +} +gravity_hostFormatGravity() { + # Format domain list as "192.168.x.x domain.com" + echo "" > "${piholeDir}/${accretionDisc}" + gravity_doHostFormat "${piholeDir}/${eventHorizon}" "${piholeDir}/${accretionDisc}" # Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it - cp ${piholeDir}/${accretionDisc} ${adList} - echo " done!" + mv "${piholeDir}/${accretionDisc}" "${adList}" +} + +gravity_hostFormatBlack() { + if [[ -f "${blacklistFile}" ]]; then + numBlacklisted=$(wc -l < "${blacklistFile}") + # Format domain list as "192.168.x.x domain.com" + gravity_doHostFormat "${blacklistFile}" "${blackList}.tmp" + # Copy the file over as /etc/pihole/black.list so dnsmasq can use it + mv "${blackList}.tmp" "${blackList}" + else + echo "::: Nothing to blacklist!" + fi } # blackbody - remove any remnant files from script processes @@ -377,11 +391,6 @@ gravity_advanced() { } gravity_reload() { - #Clear no longer needed files... - echo ":::" - echo -n "::: Cleaning up un-needed files..." - rm ${piholeDir}/pihole.*.txt - echo " done!" # Reload hosts file echo ":::" @@ -402,6 +411,7 @@ for var in "$@"; do "-f" | "--force" ) forceGrav=true;; "-h" | "--help" ) helpFunc;; "-sd" | "--skip-download" ) skipDownload=true;; + "-b" | "--blacklist-only" ) blackListOnly=true;; esac done @@ -411,22 +421,39 @@ if [[ "${forceGrav}" == true ]]; then echo " done!" fi -gravity_collapse -gravity_spinup -if [[ "${skipDownload}" == false ]]; then +if [[ ! "${blackListOnly}" == true ]]; then + gravity_collapse + gravity_spinup + if [[ "${skipDownload}" == false ]]; then gravity_Schwarzchild gravity_advanced -else + else echo "::: Using cached Event Horizon list..." numberOf=$(wc -l < ${piholeDir}/${preEventHorizon}) - echo "::: $numberOf unique domains trapped in the event horizon." + echo "::: $numberOf unique domains trapped in the event horizon." + fi + gravity_Whitelist fi -gravity_Whitelist gravity_Blacklist gravity_Wildcard -gravity_hostFormat +echo -n "::: Formatting domains into a HOSTS file..." +if [[ ! "${blackListOnly}" == true ]]; then + gravity_hostFormatLocal + gravity_hostFormatGravity +fi +gravity_hostFormatBlack +echo " done!" + gravity_blackbody +if [[ ! "${blackListOnly}" == true ]]; then + #Clear no longer needed files... + echo ":::" + echo -n "::: Cleaning up un-needed files..." + rm ${piholeDir}/pihole.*.txt + echo " done!" +fi + gravity_reload "${PIHOLE_COMMAND}" status diff --git a/pihole b/pihole index 83e13000..055d6bce 100755 --- a/pihole +++ b/pihole @@ -9,11 +9,11 @@ # Please see LICENSE file for your rights under this license. readonly PI_HOLE_SCRIPT_DIR="/opt/pihole" - readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf" + # Must be root to use this tool if [[ ! $EUID -eq 0 ]];then - if [ -x "$(command -v sudo)" ];then + if [[ -x "$(command -v sudo)" ]]; then exec sudo bash "$0" "$@" exit $? else @@ -61,7 +61,7 @@ debugFunc() { } flushFunc() { - "${PI_HOLE_SCRIPT_DIR}"/piholeLogFlush.sh + "${PI_HOLE_SCRIPT_DIR}"/piholeLogFlush.sh "$@" exit 0 } @@ -163,16 +163,16 @@ versionFunc() { restartDNS() { dnsmasqPid=$(pidof dnsmasq) - if [[ ${dnsmasqPid} ]]; then - # service already running - reload config - if [ -x "$(command -v systemctl)" ]; then + if [[ "${dnsmasqPid}" ]]; then + # Service already running - reload config + if [[ -x "$(command -v systemctl)" ]]; then systemctl restart dnsmasq else service dnsmasq restart fi else - # service not running, start it up - if [ -x "$(command -v systemctl)" ]; then + # Service not running, start it up + if [[ -x "$(command -v systemctl)" ]]; then systemctl start dnsmasq else service dnsmasq start @@ -181,16 +181,29 @@ restartDNS() { } piholeEnable() { - if [[ "${1}" == "0" ]] ; then - #Disable Pihole + if [[ "${2}" == "-h" ]] || [[ "${2}" == "--help" ]]; then + echo "Usage: pihole disable [time] +Example: 'pihole disable', or 'pihole disable 5m' +Disable Pi-hole subsystems + +Time: + #s Disable Pi-hole functionality for # second(s) + #m Disable Pi-hole functionality for # minute(s)" + exit 0 + elif [[ "${1}" == "0" ]]; then + # Disable Pi-hole sed -i 's/^addn-hosts=\/etc\/pihole\/gravity.list/#addn-hosts=\/etc\/pihole\/gravity.list/' /etc/dnsmasq.d/01-pihole.conf + sed -i 's/^addn-hosts=\/etc\/pihole\/black.list/#addn-hosts=\/etc\/pihole\/black.list/' /etc/dnsmasq.d/01-pihole.conf + if [[ -e "$wildcardlist" ]]; then + mv "$wildcardlist" "/etc/pihole/wildcard.list" + fi echo "::: Blocking has been disabled!" - if [[ $# > 1 ]] ; then - if [[ ${2} == *"s"* ]] ; then + if [[ $# > 1 ]]; then + if [[ "${2}" == *"s"* ]]; then tt=${2%"s"} echo "::: Blocking will be re-enabled in ${tt} seconds" nohup bash -c "sleep ${tt}; pihole enable" /dev/null & - elif [[ ${2} == *"m"* ]] ; then + elif [[ "${2}" == *"m"* ]]; then tt=${2%"m"} echo "::: Blocking will be re-enabled in ${tt} minutes" tt=$((${tt}*60)) @@ -204,24 +217,35 @@ piholeEnable() { fi fi else - #Enable pihole + # Enable Pi-hole echo "::: Blocking has been enabled!" sed -i 's/^#addn-hosts/addn-hosts/' /etc/dnsmasq.d/01-pihole.conf + if [[ -e "/etc/pihole/wildcard.list" ]]; then + mv "/etc/pihole/wildcard.list" "$wildcardlist" + fi fi restartDNS } piholeLogging() { shift + if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then + echo "Usage: pihole logging [options] +Example: 'pihole logging on' +Specify whether the Pi-hole log should be used - if [[ "${1}" == "off" ]] ; then - #Disable Logging +Options: + on Enable the Pi-hole log at /var/log/pihole.log + off Disable the Pi-hole log at /var/log/pihole.log" + exit 0 + elif [[ "${1}" == "off" ]]; then + # Disable logging sed -i 's/^log-queries/#log-queries/' /etc/dnsmasq.d/01-pihole.conf sed -i 's/^QUERY_LOGGING=true/QUERY_LOGGING=false/' /etc/pihole/setupVars.conf pihole -f echo "::: Logging has been disabled!" - elif [[ "${1}" == "on" ]] ; then - #Enable logging + elif [[ "${1}" == "on" ]]; then + # Enable logging sed -i 's/^#log-queries/log-queries/' /etc/dnsmasq.d/01-pihole.conf sed -i 's/^QUERY_LOGGING=false/QUERY_LOGGING=true/' /etc/pihole/setupVars.conf echo "::: Logging has been enabled!" @@ -233,12 +257,12 @@ piholeLogging() { } piholeStatus() { - if [[ $(netstat -plnt | grep -c ':53 ') > 0 ]]; then - if [[ "${1}" != "web" ]] ; then + if [[ "$(netstat -plnt | grep -c ':53 ')" -gt "0" ]]; then + if [[ "${1}" != "web" ]]; then echo "::: DNS service is running" fi else - if [[ "${1}" == "web" ]] ; then + if [[ "${1}" == "web" ]]; then echo "-1"; else echo "::: DNS service is NOT running" @@ -246,28 +270,28 @@ piholeStatus() { return fi - if [[ $(grep -i "^#addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf) ]] ; then - #list is commented out - if [[ "${1}" == "web" ]] ; then + if [[ "$(grep -i "^#addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf)" ]]; then + # List is commented out + if [[ "${1}" == "web" ]]; then echo 0; else echo "::: Pi-hole blocking is Disabled"; fi - elif [[ $(grep -i "^addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf) ]] ; then - #list set - if [[ "${1}" == "web" ]] ; then + elif [[ "$(grep -i "^addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf)" ]]; then + # List set + if [[ "${1}" == "web" ]]; then echo 1; else echo "::: Pi-hole blocking is Enabled"; fi else - #addn-host not found - if [[ "${1}" == "web" ]] ; then + # Addn-host not found + if [[ "${1}" == "web" ]]; then echo 99 else echo "::: No hosts file linked to dnsmasq, adding it in enabled state" fi - #add addn-host= to dnsmasq + # Add addn-host= to dnsmasq echo "addn-hosts=/etc/pihole/gravity.list" >> /etc/dnsmasq.d/01-pihole.conf restartDNS fi @@ -280,46 +304,96 @@ tailFunc() { } piholeCheckoutFunc() { + if [[ "$2" == "-h" ]] || [[ "$2" == "--help" ]]; then + echo "Usage: pihole checkout [repo] [branch] +Example: 'pihole checkout master' or 'pihole checkout core dev' +Switch Pi-hole subsystems to a different Github branch + +Repositories: + core [branch] Change the branch of Pi-hole's core subsystem + web [branch] Change the branch of Admin Console subsystem + +Branches: + master Update subsystems to the latest stable release + dev Update subsystems to the latest development release" + exit 0 + fi + source "${PI_HOLE_SCRIPT_DIR}"/piholeCheckout.sh shift checkout "$@" } +tricorderFunc() { + if [[ ! -p "/dev/stdin" ]]; then + echo "Please do not call Tricorder directly." + exit 1 + fi + + if ! timeout 2 nc -z tricorder.pi-hole.net 9998 &> /dev/null; then + echo "Unable to connect to Pi-hole's Tricorder server." + exit 1 + fi + + if command -v openssl &> /dev/null; then + openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin + exit "$?" + else + echo "Your debug log will be transmitted unencrypted via plain-text" + echo "There is a possibility that this could be intercepted by a third party" + echo "If you wish to cancel, press Ctrl-C to exit within 10 seconds" + secs="10" + while [[ "$secs" -gt "0" ]]; do + echo -ne "." + sleep 1 + : $((secs--)) + done + echo " " + nc tricorder.pi-hole.net 9999 < /dev/stdin + exit "$?" + fi +} + helpFunc() { - cat << EOM -::: Control all Pi-hole specific functions -::: -::: Usage: pihole [options] -::: Add -h after -w (whitelist), -b (blacklist), -c (chronometer), or -a (admin) for more information on usage -::: -::: Options: -::: -w, whitelist Whitelist domain(s) -::: -b, blacklist Blacklist domain(s) (exact match) -::: -wild, wildcard Blacklist whole domain(s) (wildcard) -::: -d, debug Start a debugging session -::: Automated debugging can be enabled with '-a'. -::: 'pihole -d -a' -::: -f, flush Flush the 'pihole.log' file -::: -t, tail Output the last lines of the 'pihole.log' file. Lines are appended as the file grows -::: -up, updatePihole Update Pi-hole components -::: -r, reconfigure Reconfigure or Repair Pi-hole -::: -g, updateGravity Update the list of ad-serving domains -::: -c, chronometer Calculates stats and displays to an LCD -::: -h, help Show this help dialog -::: -v, version Show installed versions of Pi-hole and Web-Admin -::: -q, query Query the adlists for a specific domain -::: 'pihole -q domain -exact' shows exact matches only -::: -l, logging Enable or Disable logging (pass 'on' or 'off') -::: -a, admin Admin webpage options -::: uninstall Uninstall Pi-hole from your system! :( -::: status Display if Pi-hole is Enabled or Disabled -::: enable Enable Pi-hole DNS Blocking -::: disable Disable Pi-hole DNS Blocking -::: Blocking can also be disabled only temporarily, e.g., -::: 'pihole disable 5m' - will disable blocking for 5 minutes -::: restartdns Restart dnsmasq -::: checkout Check out different branches -EOM + echo "Usage: pihole [options] +Example: 'pihole -w -h' +Add '-h' after specific commands for more information on usage + +Whitelist/Blacklist Options: + -w, whitelist Whitelist domain(s) + -b, blacklist Blacklist domain(s) + -wild, wildcard Blacklist domain(s), and all its subdomains + Add '-h' for more info on whitelist/blacklist usage + +Debugging Options: + -d, debug Start a debugging session + Add '-a' to enable automated debugging + -f, flush Flush the Pi-hole log + -r, reconfigure Reconfigure or Repair Pi-hole subsystems + -t, tail View the live output of the Pi-hole log + +Options: + -a, admin Admin Console options + Add '-h' for more info on admin console usage + -c, chronometer Calculates stats and displays to an LCD + Add '-h' for more info on chronometer usage + -g, updateGravity Update the list of ad-serving domains + -h, --help, help Show this help dialog + -l, logging Specify whether the Pi-hole log should be used + Add '-h' for more info on logging usage + -q, query Query the adlists for a specified domain + Add '-exact' AFTER a specified domain for exact match + -up, updatePihole Update Pi-hole subsystems + -v, version Show installed versions of Pi-hole, Admin Console & FTL + Add '-h' for more info on version usage + uninstall Uninstall Pi-hole from your system + status Display the running status of Pi-hole subsystems + enable Enable Pi-hole subsystems + disable Disable Pi-hole subsystems + Add '-h' for more info on disable usage + restartdns Restart Pi-hole subsystems + checkout Switch Pi-hole subsystems to a different Github branch + Add '-h' for more info on checkout usage"; exit 0 } @@ -333,7 +407,7 @@ case "${1}" in "-b" | "blacklist" ) blacklistFunc "$@";; "-wild" | "wildcard" ) wildcardFunc "$@";; "-d" | "debug" ) debugFunc "$@";; - "-f" | "flush" ) flushFunc;; + "-f" | "flush" ) flushFunc "$@";; "-up" | "updatePihole" ) updatePiholeFunc;; "-r" | "reconfigure" ) reconfigurePiholeFunc;; "-g" | "updateGravity" ) updateGravityFunc "$@";; @@ -344,11 +418,12 @@ case "${1}" in "-l" | "logging" ) piholeLogging "$@";; "uninstall" ) uninstallFunc;; "enable" ) piholeEnable 1;; - "disable" ) piholeEnable 0 $2;; + "disable" ) piholeEnable 0 "$2";; "status" ) piholeStatus "$2";; "restartdns" ) restartDNS;; "-a" | "admin" ) webpageFunc "$@";; "-t" | "tail" ) tailFunc;; "checkout" ) piholeCheckoutFunc "$@";; + "tricorder" ) tricorderFunc;; * ) helpFunc;; esac diff --git a/test/test_automated_install.py b/test/test_automated_install.py index 8e36fc96..60772625 100644 --- a/test/test_automated_install.py +++ b/test/test_automated_install.py @@ -402,6 +402,61 @@ def test_FTL_binary_installed_and_responsive_no_errors(Pihole): # assert '644 /run/pihole-FTL.pid' in support_files.stdout # assert '644 /var/log/pihole-FTL.log' in support_files.stdout +def test_IPv6_only_link_local(Pihole): + ''' confirms IPv6 blocking is disabled for Link-local address ''' + # mock ip -6 address to return Link-local address + mock_command_2('ip', {'-6 address':('inet6 fe80::d210:52fa:fe00:7ad7/64 scope link', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found neither IPv6 ULA nor GUA address, blocking IPv6 ads will not be enabled' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_only_ULA(Pihole): + ''' confirms IPv6 blocking is enabled for ULA addresses ''' + # mock ip -6 address to return ULA address + mock_command_2('ip', {'-6 address':('inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_only_GUA(Pihole): + ''' confirms IPv6 blocking is enabled for GUA addresses ''' + # mock ip -6 address to return GUA address + mock_command_2('ip', {'-6 address':('inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 GUA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_GUA_ULA_test(Pihole): + ''' confirms IPv6 blocking is enabled for GUA and ULA addresses ''' + # mock ip -6 address to return GUA and ULA addresses + mock_command_2('ip', {'-6 address':('inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global\ninet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + +def test_IPv6_ULA_GUA_test(Pihole): + ''' confirms IPv6 blocking is enabled for GUA and ULA addresses ''' + # mock ip -6 address to return ULA and GUA addresses + mock_command_2('ip', {'-6 address':('inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global\ninet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole) + detectPlatform = Pihole.run(''' + source /opt/pihole/basic-install.sh + useIPv6dialog + ''') + expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads' + assert expected_stdout in detectPlatform.stdout + # Helper functions def mock_command(script, args, container): ''' Allows for setup of commands we don't really want to have to run for real in unit tests ''' @@ -424,6 +479,27 @@ def mock_command(script, args, container): chmod +x {script} rm -f /var/log/{scriptlog}'''.format(script=full_script_path, content=mock_script, scriptlog=script)) +def mock_command_2(script, args, container): + ''' Allows for setup of commands we don't really want to have to run for real in unit tests ''' + full_script_path = '/usr/local/bin/{}'.format(script) + mock_script = dedent('''\ + #!/bin/bash -e + echo "\$0 \$@" >> /var/log/{script} + case "\$1 \$2" in'''.format(script=script)) + for k, v in args.iteritems(): + case = dedent(''' + \"{arg}\") + echo \"{res}\" + exit {retcode} + ;;'''.format(arg=k, res=v[0], retcode=v[1])) + mock_script += case + mock_script += dedent(''' + esac''') + container.run(''' + cat < {script}\n{content}\nEOF + chmod +x {script} + rm -f /var/log/{scriptlog}'''.format(script=full_script_path, content=mock_script, scriptlog=script)) + def run_script(Pihole, script): result = Pihole.run(script) assert result.rc == 0 From 5f00347019d2341cfa1a3f9e130b4ce92ae8acb9 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Mon, 26 Jun 2017 21:34:39 -0500 Subject: [PATCH 044/116] 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 045/116] 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 046/116] 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 98afb0e9980a716666031206d9955830e9f727f5 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Tue, 27 Jun 2017 14:28:05 +0200 Subject: [PATCH 047/116] pihole checkout ftl --- advanced/Scripts/piholeCheckout.sh | 125 +++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 7 deletions(-) diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh index 102db2ba..d4a85e8a 100644 --- a/advanced/Scripts/piholeCheckout.sh +++ b/advanced/Scripts/piholeCheckout.sh @@ -24,6 +24,93 @@ update="false" coltable="/opt/pihole/COL_TABLE" source ${coltable} +check_download_exists() { + status=$(curl --head --silent "https://ftl.pi-hole.net/${1}" | head -n 1) + if echo "$status" | grep -q "404"; then + return 1 + else + return 0 + fi +} + +FTLinstall() { + # Download and install FTL binary + local binary="${1}" + local path="${2}" + local str="Installing FTL" + echo -ne " ${INFO} ${str}..." + + if curl -sSL --fail "https://ftl.pi-hole.net/${path}" -o "/tmp/${binary}"; then + # Get sha1 of the binary we just downloaded for verification. + curl -sSL --fail "https://ftl.pi-hole.net/${path}.sha1" -o "/tmp/${binary}.sha1" + # Check if we just downloaded text, or a binary file. + cd /tmp + if sha1sum --status --quiet -c "${binary}".sha1; then + echo -n "transferred... " + stop_service pihole-FTL &> /dev/null + install -T -m 0755 "/tmp/${binary}" "/usr/bin/pihole-FTL" + rm "/tmp/${binary}" "/tmp/${binary}.sha1" + start_service pihole-FTL &> /dev/null + echo -e "${OVER} ${TICK} ${str}" + return 0 + else + echo -e "${OVER} ${CROSS} ${str}" + echo -e " ${COL_LIGHT_RED}Error: Download of binary from ftl.pi-hole.net failed${COL_NC}" + return 1 + fi + else + echo -e "${OVER} ${CROSS} ${str}" + echo -e " ${COL_LIGHT_RED}Error: URL not found${COL_NC}" + fi +} + +get_binary_name() { + local machine + + machine=$(uname -m) + + local str="Detecting architecture" + echo -ne " ${INFO} ${str}..." + if [[ ${machine} == arm* || ${machine} == *aarch* ]]; then + # ARM + local rev=$(uname -m | sed "s/[^0-9]//g;") + local lib=$(ldd /bin/ls | grep -E '^\s*/lib' | awk '{ print $1 }') + if [[ "$lib" == "/lib/ld-linux-aarch64.so.1" ]]; then + echo -e "${OVER} ${TICK} Detected ARM-aarch64 architecture" + binary="pihole-FTL-aarch64-linux-gnu" + elif [[ "$lib" == "/lib/ld-linux-armhf.so.3" ]]; then + if [ "$rev" -gt "6" ]; then + echo -e "${OVER} ${TICK} Detected ARM-hf architecture (armv7+)" + binary="pihole-FTL-arm-linux-gnueabihf" + else + echo -e "${OVER} ${TICK} Detected ARM-hf architecture (armv6 or lower) Using ARM binary" + binary="pihole-FTL-arm-linux-gnueabi" + fi + else + echo -e "${OVER} ${TICK} Detected ARM architecture" + binary="pihole-FTL-arm-linux-gnueabi" + fi + elif [[ $machine == ppc ]]; then + # PowerPC + echo "::: Detected PowerPC architecture" + binary="pihole-FTL-powerpc-linux-gnu" + elif [[ ${machine} == x86_64 ]]; then + # 64bit + echo -e "${OVER} ${TICK} Detected x86_64 architecture" + binary="pihole-FTL-linux-x86_64" + else + # Something else - we try to use 32bit executable and warn the user + if [[ ! ${machine} == i686 ]]; then + echo -e "${OVER} ${CROSS} ${str}... + ${COL_LIGHT_RED}Not able to detect architecture (unknown: ${machine}), trying 32bit executable + Contact support if you experience issues (e.g: FTL not running)${COL_NC}" + else + echo -e "${OVER} ${TICK} Detected 32bit (i686) architecture" + fi + binary="pihole-FTL-linux-x86_32" + fi +} + fully_fetch_repo() { # Add upstream branches to shallow clone local directory="${1}" @@ -50,7 +137,6 @@ get_available_branches() { return } - fetch_checkout_pull_branch() { # Check out specified branch local directory="${1}" @@ -74,7 +160,7 @@ checkout_pull_branch() { cd "${directory}" || return 1 oldbranch="$(git symbolic-ref HEAD)" - + git checkout "${branch}" || return 1 if [[ "$(git diff "${oldbranch}" | grep -c "^")" -gt "0" ]]; then @@ -82,13 +168,13 @@ checkout_pull_branch() { fi git_pull=$(git pull || return 1) - + if [[ "$git_pull" == *"up-to-date"* ]]; then echo -e "\n ${INFO} $(git pull)" else echo -e "$git_pull\n" fi - + return 0 } @@ -150,6 +236,12 @@ checkout() { fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; } fi echo -e " ${TICK} Pi-hole core" + + get_binary_name + local path + path="development/${binary}" + FTLinstall "${binary}" "${path}" + elif [[ "${1}" == "master" ]] ; then # Shortcut to check out master branches echo -e " ${INFO} Shortcut \"master\" detected - checking out master branches..." @@ -160,7 +252,12 @@ checkout() { fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; } fi echo -e " ${TICK} Web interface" - + + get_binary_name + local path + path="master/${binary}" + FTLinstall "${binary}" "${path}" + elif [[ "${1}" == "core" ]] ; then str="Fetching branches from ${piholeGitUrl}" echo -ne " ${INFO} $str" @@ -196,7 +293,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" @@ -215,13 +312,27 @@ checkout() { exit 1 fi checkout_pull_branch "${webInterfaceDir}" "${2}" + elif [[ "${1}" == "ftl" ]] ; then + + get_binary_name + local path + path="${2}/${binary}" + + if check_download_exists "$path"; then + echo " ${TICK} Branch ${2} exists" + else + echo " ${CROSS} Branch ${2} doesn't exist" + fi + + FTLinstall "${binary}" "${path}" + else echo -e " ${INFO} Requested option \"${1}\" is not available" exit 1 fi # Force updating everything - if [[ ! "${1}" == "web" && "${update}" == "true" ]]; then + if [[ ( ! "${1}" == "web" && ! "${1}" == "ftl" ) && "${update}" == "true" ]]; then echo -e " ${INFO} Running installer to upgrade your installation" if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then exit 0 From ab1a6d8829b2d9d86f1bc48dd2fd034dba28736d Mon Sep 17 00:00:00 2001 From: Adam Warner Date: Thu, 29 Jun 2017 02:18:52 +0100 Subject: [PATCH 048/116] 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 049/116] 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 050/116] 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 051/116] 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 052/116] 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 053/116] 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 054/116] 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 055/116] 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 056/116] 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 70fd94edb3ebcfaf16ea9d453e7ca10d7318c9ed Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 5 Jul 2017 19:30:05 +0200 Subject: [PATCH 057/116] Edit message when requested branch of FTL is not available --- advanced/Scripts/piholeCheckout.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh index d4a85e8a..7a84f588 100644 --- a/advanced/Scripts/piholeCheckout.sh +++ b/advanced/Scripts/piholeCheckout.sh @@ -321,7 +321,7 @@ checkout() { if check_download_exists "$path"; then echo " ${TICK} Branch ${2} exists" else - echo " ${CROSS} Branch ${2} doesn't exist" + echo " ${CROSS} Requested branch \"${2}\" is not available" fi FTLinstall "${binary}" "${path}" From bb8a263d70766863d73d077578ebe041f10793d1 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 5 Jul 2017 19:34:20 +0200 Subject: [PATCH 058/116] ShellCheck --- advanced/Scripts/piholeCheckout.sh | 38 +++++++++++++++++++----------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh index 7a84f588..657bde83 100644 --- a/advanced/Scripts/piholeCheckout.sh +++ b/advanced/Scripts/piholeCheckout.sh @@ -35,16 +35,19 @@ check_download_exists() { FTLinstall() { # Download and install FTL binary - local binary="${1}" - local path="${2}" - local str="Installing FTL" + local binary + binary="${1}" + local path + path="${2}" + local str + str="Installing FTL" echo -ne " ${INFO} ${str}..." if curl -sSL --fail "https://ftl.pi-hole.net/${path}" -o "/tmp/${binary}"; then # Get sha1 of the binary we just downloaded for verification. curl -sSL --fail "https://ftl.pi-hole.net/${path}.sha1" -o "/tmp/${binary}.sha1" # Check if we just downloaded text, or a binary file. - cd /tmp + cd /tmp || return 1 if sha1sum --status --quiet -c "${binary}".sha1; then echo -n "transferred... " stop_service pihole-FTL &> /dev/null @@ -66,15 +69,17 @@ FTLinstall() { get_binary_name() { local machine - machine=$(uname -m) - local str="Detecting architecture" + local str + str="Detecting architecture" echo -ne " ${INFO} ${str}..." if [[ ${machine} == arm* || ${machine} == *aarch* ]]; then # ARM - local rev=$(uname -m | sed "s/[^0-9]//g;") - local lib=$(ldd /bin/ls | grep -E '^\s*/lib' | awk '{ print $1 }') + local rev + rev=$(uname -m | sed "s/[^0-9]//g;") + local lib + lib=$(ldd /bin/ls | grep -E '^\s*/lib' | awk '{ print $1 }') if [[ "$lib" == "/lib/ld-linux-aarch64.so.1" ]]; then echo -e "${OVER} ${TICK} Detected ARM-aarch64 architecture" binary="pihole-FTL-aarch64-linux-gnu" @@ -127,7 +132,8 @@ fully_fetch_repo() { get_available_branches() { # Return available branches - local directory="${1}" + local directory + directory="${1}" local output cd "${directory}" || return 1 @@ -139,11 +145,13 @@ get_available_branches() { fetch_checkout_pull_branch() { # Check out specified branch - local directory="${1}" - local branch="${2}" + local directory + directory="${1}" + local branch + branch="${2}" # Set the reference for the requested branch, fetch, check it put and pull it - cd "${directory}" + cd "${directory}" || return 1 git remote set-branches origin "${branch}" || return 1 git stash --all --quiet &> /dev/null || true git clean --force -d || true @@ -153,8 +161,10 @@ fetch_checkout_pull_branch() { checkout_pull_branch() { # Check out specified branch - local directory="${1}" - local branch="${2}" + local directory + directory="${1}" + local branch + branch="${2}" local oldbranch cd "${directory}" || return 1 From aad39c5ffc9ed879c3327224e1bf79d121615290 Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Thu, 6 Jul 2017 19:25:56 -0500 Subject: [PATCH 059/116] 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}