mirror of
https://github.com/pi-hole/pi-hole
synced 2024-11-18 14:18:15 +00:00
af8e629df4
Change description as we want to save the debug log for 48h instead of only 24h
439 lines
13 KiB
Bash
Executable File
439 lines
13 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Pi-hole: A black hole for Internet advertisements
|
|
# (c) 2015, 2016 by Jacob Salmela
|
|
# Network-wide ad blocking via your Raspberry Pi
|
|
# http://pi-hole.net
|
|
# Generates pihole_debug.log to be used for troubleshooting.
|
|
#
|
|
# Pi-hole is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
|
|
set -o pipefail
|
|
|
|
######## GLOBAL VARS ########
|
|
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"
|
|
WHITELISTMATCHES="/tmp/whitelistmatches.list"
|
|
|
|
IPV6_READY=false
|
|
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
|
|
|
|
# Ensure the file exists, create if not, clear if exists.
|
|
truncate --size=0 "${DEBUG_LOG}"
|
|
chmod 644 ${DEBUG_LOG}
|
|
chown "$USER":pihole ${DEBUG_LOG}
|
|
|
|
source ${VARSFILE}
|
|
|
|
### Private functions exist here ###
|
|
log_write() {
|
|
echo "${1}" >> "${DEBUG_LOG}"
|
|
}
|
|
|
|
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}" ]] && 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
|
|
error_found=0
|
|
|
|
local pi_hole_ver="$(cd /etc/.pihole/ && git describe --tags --abbrev=0)" \
|
|
&& log_echo -r "Pi-hole: $pi_hole_ver" || (log_echo "Pi-hole git repository not detected." && error_found=1)
|
|
local admin_ver="$(cd /var/www/html/admin && git describe --tags --abbrev=0)" \
|
|
&& log_echo -r "WebUI: $admin_ver" || (log_echo "Pi-hole Admin Pages git repository not detected." && error_found=1)
|
|
local light_ver="$(lighttpd -v |& head -n1 | cut -d " " -f1)" \
|
|
&& log_echo -r "${light_ver}" || (log_echo "lighttpd not installed." && error_found=1)
|
|
local php_ver="$(php -v |& head -n1)" \
|
|
&& log_echo -r "${php_ver}" || (log_echo "PHP not installed." && error_found=1)
|
|
|
|
(local pi_hole_branch="$(cd /etc/.pihole/ && git rev-parse --abbrev-ref HEAD)" && log_echo -r "Pi-hole branch: ${pi_hole_branch}") || log_echo "Unable to obtain Pi-hole branch"
|
|
(local pi_hole_rev="$(cd /etc/.pihole/ && git describe --long --dirty --tags)" && log_echo -r "Pi-hole rev: ${pi_hole_rev}") || log_echo "Unable to obtain Pi-hole revision"
|
|
|
|
(local admin_branch="$(cd /var/www/html/admin && git rev-parse --abbrev-ref HEAD)" && log_echo -r "AdminLTE branch: ${admin_branch}") || log_echo "Unable to obtain AdminLTE branch"
|
|
(local admin_rev="$(cd /var/www/html/admin && git describe --long --dirty --tags)" && log_echo -r "AdminLTE rev: ${admin_rev}") || log_echo "Unable to obtain AdminLTE revision"
|
|
|
|
return "${error_found}"
|
|
}
|
|
|
|
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 && IPV6_READY=true
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
|
|
ip_check() {
|
|
header_write "IP Address Information"
|
|
# Get the current interface for Internet traffic
|
|
|
|
# Check if IPv6 enabled
|
|
local IPv6_interface
|
|
local IPv4_interface
|
|
ipv6_check && IPv6_interface=${piholeInterface:-$(ip -6 r | grep default | cut -d ' ' -f 5)}
|
|
# If declared in setupVars.conf use it, otherwise defer to default
|
|
# http://stackoverflow.com/questions/2013547/assigning-default-values-to-shell-variables-with-a-single-command-in-bash
|
|
IPv4_interface=${piholeInterface:-$(ip r | grep default | cut -d ' ' -f 5)}
|
|
|
|
|
|
if [[ IPV6_READY ]]; then
|
|
local IPv6_addr_list="$(ip a | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "inet6") print $(i+1) }')" \
|
|
&& (log_write "${IPv6_addr_list}" && echo "::: IPv6 addresses located") \
|
|
|| log_echo "No IPv6 addresses found."
|
|
|
|
local IPv6_def_gateway=$(ip -6 r | grep default | cut -d ' ' -f 3)
|
|
if [[ $? = 0 ]] && [[ -n ${IPv6_def_gateway} ]]; then
|
|
echo -n "::: Pinging default IPv6 gateway: "
|
|
local IPv6_def_gateway_check="$(ping6 -q -W 3 -c 3 -n "${IPv6_def_gateway}" -I "${IPv6_interface}"| tail -n3)" \
|
|
&& echo "Gateway Responded." \
|
|
|| echo "Gateway did not respond."
|
|
block_parse "${IPv6_def_gateway_check}"
|
|
|
|
echo -n "::: Pinging Internet via IPv6: "
|
|
local IPv6_inet_check=$(ping6 -q -W 3 -c 3 -n 2001:4860:4860::8888 -I "${IPv6_interface}"| tail -n3) \
|
|
&& echo "Query responded." \
|
|
|| echo "Query did not respond."
|
|
block_parse "${IPv6_inet_check}"
|
|
else
|
|
log_echo="No IPv6 Gateway Detected"
|
|
fi
|
|
|
|
local IPv4_addr_list="$(ip a | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "inet") print $(i+1) }')" \
|
|
&& (block_parse "${IPv4_addr_list}" && echo "::: IPv4 addresses located")\
|
|
|| log_echo "No IPv4 addresses found."
|
|
|
|
local IPv4_def_gateway=$(ip r | grep default | cut -d ' ' -f 3)
|
|
if [[ $? = 0 ]]; then
|
|
echo -n "::: Pinging default IPv4 gateway: "
|
|
local IPv4_def_gateway_check="$(ping -q -w 3 -c 3 -n "${IPv4_def_gateway}" -I "${IPv4_interface}" | tail -n3)" \
|
|
&& echo "Gateway responded." \
|
|
|| echo "Gateway did not respond."
|
|
block_parse "${IPv4_def_gateway_check}"
|
|
|
|
echo -n "::: Pinging Internet via IPv4: "
|
|
local IPv4_inet_check="$(ping -q -w 5 -c 3 -n 8.8.8.8 -I "${IPv4_interface}" | tail -n3)" \
|
|
&& echo "Query responded." \
|
|
|| echo "Query did not respond."
|
|
block_parse "${IPv4_inet_check}"
|
|
fi
|
|
|
|
fi
|
|
}
|
|
|
|
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() {
|
|
header_write "Resolver Functions Check"
|
|
|
|
# Find a blocked url that has not been whitelisted.
|
|
TESTURL="doubleclick.com"
|
|
if [ -s "${WHITELISTMATCHES}" ]; then
|
|
while read -r line; do
|
|
CUTURL=${line#*" "}
|
|
if [ "${CUTURL}" != "Pi-Hole.IsWorking.OK" ]; then
|
|
while read -r line2; do
|
|
CUTURL2=${line2#*" "}
|
|
if [ "${CUTURL}" != "${CUTURL2}" ]; then
|
|
TESTURL="${CUTURL}"
|
|
break 2
|
|
fi
|
|
done < "${WHITELISTMATCHES}"
|
|
fi
|
|
done < "${GRAVITYFILE}"
|
|
fi
|
|
|
|
log_write "Resolution of ${TESTURL} from Pi-hole:"
|
|
LOCALDIG=$(dig "${TESTURL}" @127.0.0.1)
|
|
if [[ $? = 0 ]]; then
|
|
log_write "${LOCALDIG}"
|
|
else
|
|
log_write "Failed to resolve ${TESTURL} on Pi-hole"
|
|
fi
|
|
log_write ""
|
|
|
|
|
|
log_write "Resolution of ${TESTURL} from 8.8.8.8:"
|
|
REMOTEDIG=$(dig "${TESTURL}" @8.8.8.8)
|
|
if [[ $? = 0 ]]; then
|
|
log_write "${REMOTEDIG}"
|
|
else
|
|
log_write "Failed to resolve ${TESTURL} on 8.8.8.8"
|
|
fi
|
|
log_write ""
|
|
|
|
log_write "Pi-hole dnsmasq specific records lookups"
|
|
log_write "Cache Size:"
|
|
dig +short chaos txt cachesize.bind >> ${DEBUG_LOG}
|
|
log_write "Upstream Servers:"
|
|
dig +short chaos txt servers.bind >> ${DEBUG_LOG}
|
|
log_write ""
|
|
}
|
|
|
|
checkProcesses() {
|
|
header_write "Processes Check"
|
|
|
|
echo "::: Logging status of lighttpd and dnsmasq..."
|
|
PROCESSES=( lighttpd dnsmasq )
|
|
for i in "${PROCESSES[@]}"; do
|
|
log_write ""
|
|
log_write "${i}"
|
|
log_write " processes status:"
|
|
systemctl -l status "${i}" >> "${DEBUG_LOG}"
|
|
done
|
|
log_write ""
|
|
}
|
|
|
|
debugLighttpd() {
|
|
echo "::: Checking for necessary lighttpd files."
|
|
files_check "${LIGHTTPDFILE}"
|
|
files_check "${LIGHTTPDERRFILE}"
|
|
echo ":::"
|
|
}
|
|
|
|
countdown() {
|
|
tuvix=${TIMEOUT}
|
|
printf "::: Logging will automatically teminate in ${TIMEOUT} seconds\n"
|
|
while [ $tuvix -ge 1 ]
|
|
do
|
|
printf ":::\t${tuvix} seconds left. \r"
|
|
sleep 5
|
|
tuvix=$(( tuvix - 5 ))
|
|
done
|
|
}
|
|
### END FUNCTIONS ###
|
|
|
|
# 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
|
|
|
|
daemon_check lighttpd http
|
|
daemon_check dnsmasq domain
|
|
checkProcesses
|
|
testResolver
|
|
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!"
|
|
|
|
|
|
# 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}" >> ${DEBUG_LOG}
|
|
else
|
|
log_write "No pihole.log file found!"
|
|
printf ":::\tNo pihole.log file found!\n"
|
|
fi
|
|
}
|
|
|
|
# Anything to be done after capturing of pihole.log terminates
|
|
finalWork() {
|
|
local tricorder
|
|
echo "::: Finshed debugging!"
|
|
echo "::: The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only."
|
|
read -r -p "::: Would you like to upload the log? [y/N] " response
|
|
case ${response} in
|
|
[yY][eE][sS]|[yY])
|
|
tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999)
|
|
;;
|
|
*)
|
|
echo "::: Log will NOT be uploaded to tricorder."
|
|
;;
|
|
esac
|
|
|
|
# Check if tricorder.pi-hole.net is reachable and provide token.
|
|
if [ -n "${tricorder}" ]; then
|
|
echo "::: Your debug token is : ${tricorder}"
|
|
echo "::: Please contact the Pi-hole team with your token 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"
|
|
}
|
|
|
|
trap finalWork EXIT
|
|
|
|
### Method calls for additional logging ###
|
|
dumpPiHoleLog
|