diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 3ac63e80..dc4a2729 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -467,6 +467,9 @@ diagnose_operating_system() { # Display the current test that is running echo_current_diagnostic "Operating system" + # If the PIHOLE_DOCKER_TAG variable is set, include this information in the debug output + [ -n "${PIHOLE_DOCKER_TAG}" ] && log_write "${INFO} Pi-hole Docker Container: ${PIHOLE_DOCKER_TAG}" + # If there is a /etc/*release file, it's probably a supported operating system, so we can if ls /etc/*release 1> /dev/null 2>&1; then # display the attributes to the user from the function made earlier @@ -730,11 +733,11 @@ compare_port_to_service_assigned() { # If the service is a Pi-hole service, highlight it in green if [[ "${service_name}" == "${expected_service}" ]]; then - log_write "[${COL_GREEN}${port}${COL_NC}] is in use by ${COL_GREEN}${service_name}${COL_NC}" + log_write "${TICK} ${COL_GREEN}${port}${COL_NC} is in use by ${COL_GREEN}${service_name}${COL_NC}" # Otherwise, else # Show the service name in red since it's non-standard - log_write "[${COL_RED}${port}${COL_NC}] is in use by ${COL_RED}${service_name}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_PORTS})" + log_write "${CROSS} ${COL_RED}${port}${COL_NC} is in use by ${COL_RED}${service_name}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_PORTS})" fi } @@ -750,32 +753,28 @@ check_required_ports() { # Sort the addresses and remove duplicates while IFS= read -r line; do ports_in_use+=( "$line" ) - done < <( lsof -iTCP -sTCP:LISTEN -P -n +c 10 ) + done < <( ss --listening --numeric --tcp --udp --processes --oneline --no-header ) # Now that we have the values stored, for i in "${!ports_in_use[@]}"; do # loop through them and assign some local variables local service_name - service_name=$(echo "${ports_in_use[$i]}" | awk '{print $1}') + service_name=$(echo "${ports_in_use[$i]}" | awk '{gsub(/users:\(\("/,"",$7);gsub(/".*/,"",$7);print $7}') local protocol_type - protocol_type=$(echo "${ports_in_use[$i]}" | awk '{print $5}') + protocol_type=$(echo "${ports_in_use[$i]}" | awk '{print $1}') local port_number - port_number="$(echo "${ports_in_use[$i]}" | awk '{print $9}')" + port_number="$(echo "${ports_in_use[$i]}" | awk '{print $5}')" # | awk '{gsub(/^.*:/,"",$5);print $5}') - # Skip the line if it's the titles of the columns the lsof command produces - if [[ "${service_name}" == COMMAND ]]; then - continue - fi # Use a case statement to determine if the right services are using the right ports - case "$(echo "$port_number" | rev | cut -d: -f1 | rev)" in - 53) compare_port_to_service_assigned "${resolver}" "${service_name}" 53 + case "$(echo "${port_number}" | rev | cut -d: -f1 | rev)" in + 53) compare_port_to_service_assigned "${resolver}" "${service_name}" "${protocol_type}:${port_number}" ;; - 80) compare_port_to_service_assigned "${web_server}" "${service_name}" 80 + 80) compare_port_to_service_assigned "${web_server}" "${service_name}" "${protocol_type}:${port_number}" ;; - 4711) compare_port_to_service_assigned "${ftl}" "${service_name}" 4711 + 4711) compare_port_to_service_assigned "${ftl}" "${service_name}" "${protocol_type}:${port_number}" ;; # If it's not a default port that Pi-hole needs, just print it out for the user to see - *) log_write "${port_number} ${service_name} (${protocol_type})"; + *) log_write " ${protocol_type}:${port_number} is in use by ${service_name:=}"; esac done } @@ -1386,9 +1385,9 @@ upload_to_tricorder() { log_write "${TICK} ${COL_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 " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only." - # If pihole -d is running automatically (usually through the dashboard) + # If pihole -d is running automatically if [[ "${AUTOMATED}" ]]; then # let the user know log_write "${INFO} Debug script running in automated mode" @@ -1396,16 +1395,19 @@ upload_to_tricorder() { curl_to_tricorder # 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 (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 - [yY][eE][sS]|[yY]) curl_to_tricorder;; - # If they choose no, just exit out of the script - *) log_write " * Log will ${COL_GREEN}NOT${COL_NC} be uploaded to tricorder.\\n * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG}${COL_NC}\\n";exit; - esac + # if not being called from the web interface + if [[ ! "${WEBCALL}" ]]; then + echo "" + # 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 + [yY][eE][sS]|[yY]) curl_to_tricorder;; + # If they choose no, just exit out of the script + *) log_write " * Log will ${COL_GREEN}NOT${COL_NC} be uploaded to tricorder.\\n * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG}${COL_NC}\\n";exit; + esac + fi fi # Check if tricorder.pi-hole.net is reachable and provide token # along with some additional useful information @@ -1425,8 +1427,13 @@ upload_to_tricorder() { # If no token was generated else # Show an error and some help instructions - log_write "${CROSS} ${COL_RED}There was an error uploading your debug log.${COL_NC}" - log_write " * Please try again or contact the Pi-hole team for assistance." + # Skip this if being called from web interface and autmatic mode was not chosen (users opt-out to upload) + if [[ "${WEBCALL}" ]] && [[ ! "${AUTOMATED}" ]]; then + : + else + log_write "${CROSS} ${COL_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 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" diff --git a/advanced/Templates/pihole-FTL.conf b/advanced/Templates/pihole-FTL.conf new file mode 100644 index 00000000..269fcf9d --- /dev/null +++ b/advanced/Templates/pihole-FTL.conf @@ -0,0 +1,2 @@ +#; Pi-hole FTL config file +#; Comments should start with #; to avoid issues with PHP and bash reading this file diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index bd2bf4c3..3780f7b0 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -287,7 +287,7 @@ package_manager_detect() { # Packages required to run this install script (stored as an array) INSTALLER_DEPS=(git iproute2 whiptail ca-certificates) # Packages required to run Pi-hole (stored as an array) - PIHOLE_DEPS=(cron curl iputils-ping lsof psmisc sudo unzip idn2 sqlite3 libcap2-bin dns-root-data libcap2) + PIHOLE_DEPS=(cron curl iputils-ping psmisc sudo unzip idn2 sqlite3 libcap2-bin dns-root-data libcap2 netcat) # Packages required for the Web admin interface (stored as an array) # It's useful to separate this from Pi-hole, since the two repos are also setup separately PIHOLE_WEB_DEPS=(lighttpd "${phpVer}-common" "${phpVer}-cgi" "${phpVer}-sqlite3" "${phpVer}-xml" "${phpVer}-intl") @@ -332,7 +332,7 @@ package_manager_detect() { PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l" OS_CHECK_DEPS=(grep bind-utils) INSTALLER_DEPS=(git iproute newt procps-ng which chkconfig ca-certificates) - PIHOLE_DEPS=(cronie curl findutils sudo unzip libidn2 psmisc sqlite libcap lsof) + PIHOLE_DEPS=(cronie curl findutils sudo unzip libidn2 psmisc sqlite libcap nmap-ncat) PIHOLE_WEB_DEPS=(lighttpd lighttpd-fastcgi php-common php-cli php-pdo php-xml php-json php-intl) LIGHTTPD_USER="lighttpd" LIGHTTPD_GROUP="lighttpd" @@ -1299,10 +1299,10 @@ installConfigs() { echo "${DNS_SERVERS}" > "${PI_HOLE_CONFIG_DIR}/dns-servers.conf" chmod 644 "${PI_HOLE_CONFIG_DIR}/dns-servers.conf" - # Install empty file if it does not exist + # Install template file if it does not exist if [[ ! -r "${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf" ]]; then install -d -m 0755 ${PI_HOLE_CONFIG_DIR} - if ! install -o pihole -m 664 /dev/null "${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf" &>/dev/null; then + if ! install -T -o pihole -m 664 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.conf" "${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf" &>/dev/null; then printf " %bError: Unable to initialize configuration file %s/pihole-FTL.conf\\n" "${COL_LIGHT_RED}" "${PI_HOLE_CONFIG_DIR}" return 1 fi @@ -1334,7 +1334,7 @@ installConfigs() { chmod 644 /etc/lighttpd/external.conf # If there is a custom block page in the html/pihole directory, replace 404 handler in lighttpd config if [[ -f "${PI_HOLE_BLOCKPAGE_DIR}/custom.php" ]]; then - sed -i 's/^\(server\.error-handler-404\s*=\s*\).*$/\1"pihole\/custom\.php"/' "${lighttpdConfig}" + sed -i 's/^\(server\.error-handler-404\s*=\s*\).*$/\1"\/pihole\/custom\.php"/' "${lighttpdConfig}" fi # Make the directories if they do not exist and set the owners mkdir -p /run/lighttpd @@ -1731,7 +1731,7 @@ finalExports() { # If the setup variable file exists, if [[ -e "${setupVars}" ]]; then # update the variables in the file - sed -i.update.bak '/PIHOLE_INTERFACE/d;/IPV4_ADDRESS/d;/IPV6_ADDRESS/d;/PIHOLE_DNS_1\b/d;/PIHOLE_DNS_2\b/d;/QUERY_LOGGING/d;/INSTALL_WEB_SERVER/d;/INSTALL_WEB_INTERFACE/d;/LIGHTTPD_ENABLED/d;/CACHE_SIZE/d;/DNS_FQDN_REQUIRED/d;/DNS_BOGUS_PRIV/d;' "${setupVars}" + sed -i.update.bak '/PIHOLE_INTERFACE/d;/IPV4_ADDRESS/d;/IPV6_ADDRESS/d;/PIHOLE_DNS_1\b/d;/PIHOLE_DNS_2\b/d;/QUERY_LOGGING/d;/INSTALL_WEB_SERVER/d;/INSTALL_WEB_INTERFACE/d;/LIGHTTPD_ENABLED/d;/CACHE_SIZE/d;/DNS_FQDN_REQUIRED/d;/DNS_BOGUS_PRIV/d;/DNSMASQ_LISTENING/d;' "${setupVars}" fi # echo the information to the user { @@ -1747,6 +1747,7 @@ finalExports() { echo "CACHE_SIZE=${CACHE_SIZE}" echo "DNS_FQDN_REQUIRED=${DNS_FQDN_REQUIRED:-true}" echo "DNS_BOGUS_PRIV=${DNS_BOGUS_PRIV:-true}" + echo "DNSMASQ_LISTENING=${DNSMASQ_LISTENING:-local}" }>> "${setupVars}" chmod 644 "${setupVars}" @@ -2277,7 +2278,7 @@ FTLcheckUpdate() { printf " %b Checking for existing FTL binary...\\n" "${INFO}" local ftlLoc - ftlLoc=$(which pihole-FTL 2>/dev/null) + ftlLoc=$(command -v pihole-FTL 2>/dev/null) local ftlBranch @@ -2315,7 +2316,7 @@ FTLcheckUpdate() { # We already have a pihole-FTL binary downloaded. # Alt branches don't have a tagged version against them, so just confirm the checksum of the local vs remote to decide whether we download or not remoteSha1=$(curl -sSL --fail "https://ftl.pi-hole.net/${ftlBranch}/${binary}.sha1" | cut -d ' ' -f 1) - localSha1=$(sha1sum "$(which pihole-FTL)" | cut -d ' ' -f 1) + localSha1=$(sha1sum "$(command -v pihole-FTL)" | cut -d ' ' -f 1) if [[ "${remoteSha1}" != "${localSha1}" ]]; then printf " %b Checksums do not match, downloading from ftl.pi-hole.net.\\n" "${INFO}" @@ -2345,7 +2346,7 @@ FTLcheckUpdate() { printf " %b Latest FTL Binary already installed (%s). Confirming Checksum...\\n" "${INFO}" "${FTLlatesttag}" remoteSha1=$(curl -sSL --fail "https://github.com/pi-hole/FTL/releases/download/${FTLversion%$'\r'}/${binary}.sha1" | cut -d ' ' -f 1) - localSha1=$(sha1sum "$(which pihole-FTL)" | cut -d ' ' -f 1) + localSha1=$(sha1sum "$(command -v pihole-FTL)" | cut -d ' ' -f 1) if [[ "${remoteSha1}" != "${localSha1}" ]]; then printf " %b Corruption detected...\\n" "${INFO}" diff --git a/pihole b/pihole index 055bd702..8af47dc8 100755 --- a/pihole +++ b/pihole @@ -283,27 +283,29 @@ Options: } analyze_ports() { + local lv4 lv6 port=${1} # FTL is listening at least on at least one port when this # function is getting called - echo -e " ${TICK} DNS service is listening" # Check individual address family/protocol combinations # For a healthy Pi-hole, they should all be up (nothing printed) - if grep -q "IPv4.*UDP" <<< "${1}"; then + lv4="$(ss --ipv4 --listening --numeric --tcp --udp src :${port})" + if grep -q "udp " <<< "${lv4}"; then echo -e " ${TICK} UDP (IPv4)" else echo -e " ${CROSS} UDP (IPv4)" fi - if grep -q "IPv4.*TCP" <<< "${1}"; then + if grep -q "tcp " <<< "${lv4}"; then echo -e " ${TICK} TCP (IPv4)" else echo -e " ${CROSS} TCP (IPv4)" fi - if grep -q "IPv6.*UDP" <<< "${1}"; then + lv6="$(ss --ipv6 --listening --numeric --tcp --udp src :${port})" + if grep -q "udp " <<< "${lv6}"; then echo -e " ${TICK} UDP (IPv6)" else echo -e " ${CROSS} UDP (IPv6)" fi - if grep -q "IPv6.*TCP" <<< "${1}"; then + if grep -q "tcp " <<< "${lv6}"; then echo -e " ${TICK} TCP (IPv6)" else echo -e " ${CROSS} TCP (IPv6)" @@ -312,19 +314,31 @@ analyze_ports() { } statusFunc() { - # Determine if there is a pihole service is listening on port 53 - local listening - listening="$(lsof -Pni:53)" - if grep -q "pihole" <<< "${listening}"; then - if [[ "${1}" != "web" ]]; then - analyze_ports "${listening}" - fi - else + # Determine if there is pihole-FTL service is listening + local listening pid port + + pid="$(getFTLPID)" + if [[ "$pid" -eq "-1" ]]; then case "${1}" in "web") echo "-1";; - *) echo -e " ${CROSS} DNS service is NOT listening";; + *) echo -e " ${CROSS} DNS service is NOT running";; esac return 0 + else + #get the port pihole-FTL is listening on by using FTL's telnet API + port="$(echo ">dns-port >quit" | nc 127.0.0.1 4711)" + if [[ "${port}" == "0" ]]; then + case "${1}" in + "web") echo "-1";; + *) echo -e " ${CROSS} DNS service is NOT listening";; + esac + return 0 + else + if [[ "${1}" != "web" ]]; then + echo -e " ${TICK} FTL is listening on port ${port}" + analyze_ports "${port}" + fi + fi fi # Determine if Pi-hole's blocking is enabled @@ -337,18 +351,19 @@ statusFunc() { elif grep -q "BLOCKING_ENABLED=true" /etc/pihole/setupVars.conf; then # Configs are set case "${1}" in - "web") echo 1;; + "web") echo "$port";; *) echo -e " ${TICK} Pi-hole blocking is enabled";; esac else # No configs were found case "${1}" in - "web") echo 99;; + "web") echo -2;; *) echo -e " ${INFO} Pi-hole blocking will be enabled";; esac # Enable blocking "${PI_HOLE_BIN_DIR}"/pihole enable fi + } tailFunc() {