diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..3a75dc12 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +patreon: pihole +custom: https://pi-hole.net/donate diff --git a/advanced/Scripts/database_migration/gravity-db.sh b/advanced/Scripts/database_migration/gravity-db.sh index f37ce176..a82d0d51 100644 --- a/advanced/Scripts/database_migration/gravity-db.sh +++ b/advanced/Scripts/database_migration/gravity-db.sh @@ -11,9 +11,12 @@ # Please see LICENSE file for your rights under this license. upgrade_gravityDB(){ - local database auditFile version + local database piholeDir auditFile version database="${1}" - auditFile="${2}" + piholeDir="${2}" + auditFile="${piholeDir}/auditlog.list" + + # Get database version version="$(sqlite3 "${database}" "SELECT \"value\" FROM \"info\" WHERE \"property\" = 'version';")" if [[ "$version" == "1" ]]; then diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 7ba03a37..c9280f45 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -94,7 +94,35 @@ 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_GRAVITY_DB_FILE="${PIHOLE_DIRECTORY}/gravity.db" +PIHOLE_FTL_CONF_FILE="${PIHOLE_DIRECTORY}/pihole-FTL.conf" + +# Read the value of an FTL config key. The value is printed to stdout. +# +# Args: +# 1. The key to read +# 2. The default if the setting or config does not exist +get_ftl_conf_value() { + local key=$1 + local default=$2 + local value + + # Obtain key=... setting from pihole-FTL.conf + if [[ -e "$PIHOLE_FTL_CONF_FILE" ]]; then + # Constructed to return nothing when + # a) the setting is not present in the config file, or + # b) the setting is commented out (e.g. "#DBFILE=...") + value="$(sed -n -e "s/^\\s*$key=\\s*//p" ${PIHOLE_FTL_CONF_FILE})" + fi + + # Test for missing value. Use default value in this case. + if [[ -z "$value" ]]; then + value="$default" + fi + + echo "$value" +} + +PIHOLE_GRAVITY_DB_FILE="$(get_ftl_conf_value "GRAVITYDB" "${PIHOLE_DIRECTORY}/gravity.db")" PIHOLE_COMMAND="${BIN_DIRECTORY}/pihole" PIHOLE_COLTABLE_FILE="${BIN_DIRECTORY}/COL_TABLE" @@ -105,7 +133,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_FTL_LOG="${LOG_DIRECTORY}/pihole-FTL.log" +PIHOLE_FTL_LOG="$(get_ftl_conf_value "LOGFILE" "${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" diff --git a/advanced/Scripts/query.sh b/advanced/Scripts/query.sh index 035adaac..f40adfbf 100755 --- a/advanced/Scripts/query.sh +++ b/advanced/Scripts/query.sh @@ -115,7 +115,9 @@ scanDatabaseTable() { wbMatch=true # Print table name - echo " ${matchType^} found in ${COL_BOLD}${table^}${COL_NC}" + if [[ -z "${blockpage}" ]]; then + echo " ${matchType^} found in ${COL_BOLD}${table^}${COL_NC}" + fi # Loop over results and print them mapfile -t results <<< "${result}" @@ -160,7 +162,7 @@ scanRegexDatabaseTable() { # shellcheck disable=SC2001 echo "${str_result}" | sed 's/^/ /' else - echo "π Regex ${list}" + echo "π .wildcard" exit 0 fi fi diff --git a/advanced/Scripts/webpage.sh b/advanced/Scripts/webpage.sh index 227363f0..9db10bda 100755 --- a/advanced/Scripts/webpage.sh +++ b/advanced/Scripts/webpage.sh @@ -560,8 +560,7 @@ addAudit() domains="" for domain in "$@" do - # Insert only the domain here. The date_added field will be - # filled with its default value (date_added = current timestamp) + # Check domain to be added. Only continue if it is valid validDomain="$(checkDomain "${domain}")" if [[ -n "${validDomain}" ]]; then # Put comma in between domains when there is @@ -574,6 +573,8 @@ addAudit() domains="${domains}('${domain}')" fi done + # Insert only the domain here. The date_added field will be + # filled with its default value (date_added = current timestamp) sqlite3 "${gravityDBfile}" "INSERT INTO domain_audit (domain) VALUES ${domains};" } diff --git a/advanced/index.php b/advanced/index.php index 78135e1a..62e45091 100644 --- a/advanced/index.php +++ b/advanced/index.php @@ -102,20 +102,30 @@ if ($blocklistglob === array()) { die("[ERROR] There are no domain lists generated lists within /etc/pihole/! Please update gravity by running pihole -g, or repair Pi-hole using pihole -r."); } -// Set location of adlists file -if (is_file("/etc/pihole/adlists.list")) { - $adLists = "/etc/pihole/adlists.list"; -} elseif (is_file("/etc/pihole/adlists.default")) { - $adLists = "/etc/pihole/adlists.default"; +// Get possible non-standard location of FTL's database +$FTLsettings = parse_ini_file("/etc/pihole/pihole-FTL.conf"); +if (isset($FTLsettings["GRAVITYDB"])) { + $gravityDBFile = $FTLsettings["GRAVITYDB"]; } else { - die("[ERROR] File not found: /etc/pihole/adlists.list"); + $gravityDBFile = "/etc/pihole/gravity.db"; } -// Get all URLs starting with "http" or "www" from adlists and re-index array numerically -$adlistsUrls = array_values(preg_grep("/(^http)|(^www)/i", file($adLists, FILE_IGNORE_NEW_LINES))); +// Connect to gravity.db +try { + $db = new SQLite3($gravityDBFile, SQLITE3_OPEN_READONLY); +} catch (Exception $exception) { + die("[ERROR]: Failed to connect to gravity.db"); +} + +// Get all adlist addresses +$adlistResults = $db->query("SELECT address FROM vw_adlist"); +$adlistsUrls = array(); +while ($row = $adlistResults->fetchArray()) { + array_push($adlistsUrls, $row[0]); +} if (empty($adlistsUrls)) - die("[ERROR]: There are no adlist URL's found within $adLists"); + die("[ERROR]: There are no adlists enabled"); // Get total number of blocklists (Including Whitelist, Blacklist & Wildcard lists) $adlistsCount = count($adlistsUrls) + 3; diff --git a/advanced/lighttpd.conf.debian b/advanced/lighttpd.conf.debian index 47bdbee0..2215bbdb 100644 --- a/advanced/lighttpd.conf.debian +++ b/advanced/lighttpd.conf.debian @@ -27,7 +27,7 @@ server.modules = ( ) server.document-root = "/var/www/html" -server.error-handler-404 = "pihole/index.php" +server.error-handler-404 = "/pihole/index.php" server.upload-dirs = ( "/var/cache/lighttpd/uploads" ) server.errorlog = "/var/log/lighttpd/error.log" server.pid-file = "/var/run/lighttpd.pid" diff --git a/advanced/lighttpd.conf.fedora b/advanced/lighttpd.conf.fedora index 27bc33cc..4232c90f 100644 --- a/advanced/lighttpd.conf.fedora +++ b/advanced/lighttpd.conf.fedora @@ -28,7 +28,7 @@ server.modules = ( ) server.document-root = "/var/www/html" -server.error-handler-404 = "pihole/index.php" +server.error-handler-404 = "/pihole/index.php" server.upload-dirs = ( "/var/cache/lighttpd/uploads" ) server.errorlog = "/var/log/lighttpd/error.log" server.pid-file = "/var/run/lighttpd.pid" diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index 7dbdc596..25c66ab7 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -84,8 +84,13 @@ if [ -z "${USER}" ]; then fi -# Find the rows and columns will default to 80x24 if it can not be detected -screen_size=$(stty size || printf '%d %d' 24 80) +# Check if we are running on a real terminal and find the rows and columns +# If there is no real terminal, we will default to 80x24 +if [ -t 0 ] ; then + screen_size=$(stty size) +else + screen_size="24 80" +fi # Set rows variable to contain first number printf -v rows '%d' "${screen_size%% *}" # Set columns variable to contain second number @@ -283,7 +288,7 @@ elif is_command rpm ; then UPDATE_PKG_CACHE=":" PKG_INSTALL=("${PKG_MANAGER}" install -y) PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l" - INSTALLER_DEPS=(dialog git iproute newt procps-ng which) + INSTALLER_DEPS=(dialog git iproute newt procps-ng which chkconfig) PIHOLE_DEPS=(bind-utils cronie curl findutils nmap-ncat sudo unzip wget libidn2 psmisc sqlite libcap) PIHOLE_WEB_DEPS=(lighttpd lighttpd-fastcgi php-common php-cli php-pdo) LIGHTTPD_USER="lighttpd" @@ -934,7 +939,7 @@ valid_ip() { # and set the new one to a dot (period) IFS='.' # Put the IP into an array - ip=("${ip}") + read -r -a ip <<< "${ip}" # Restore the IFS to what it was IFS=${OIFS} ## Evaluate each octet by checking if it's less than or equal to 255 (the max for each octet) @@ -1177,12 +1182,11 @@ chooseBlocklists() { mv "${adlistFile}" "${adlistFile}.old" fi # Let user select (or not) blocklists via a checklist - cmd=(whiptail --separate-output --checklist "Pi-hole relies on third party lists in order to block ads.\\n\\nYou can use the suggestions below, and/or add your own after installation\\n\\nTo deselect any list, use the arrow keys and spacebar" "${r}" "${c}" 7) + cmd=(whiptail --separate-output --checklist "Pi-hole relies on third party lists in order to block ads.\\n\\nYou can use the suggestions below, and/or add your own after installation\\n\\nTo deselect any list, use the arrow keys and spacebar" "${r}" "${c}" 6) # In an array, show the options available (all off by default): options=(StevenBlack "StevenBlack's Unified Hosts List" on MalwareDom "MalwareDomains" on Cameleon "Cameleon" on - ZeusTracker "ZeusTracker" on DisconTrack "Disconnect.me Tracking" on DisconAd "Disconnect.me Ads" on HostsFile "Hosts-file.net Ads" on) @@ -1205,7 +1209,6 @@ appendToListsFile() { StevenBlack ) echo "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" >> "${adlistFile}";; MalwareDom ) echo "https://mirror1.malwaredomains.com/files/justdomains" >> "${adlistFile}";; Cameleon ) echo "http://sysctl.org/cameleon/hosts" >> "${adlistFile}";; - ZeusTracker ) echo "https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist" >> "${adlistFile}";; DisconTrack ) echo "https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt" >> "${adlistFile}";; DisconAd ) echo "https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt" >> "${adlistFile}";; HostsFile ) echo "https://hosts-file.net/ad_servers.txt" >> "${adlistFile}";; @@ -1223,7 +1226,6 @@ installDefaultBlocklists() { appendToListsFile StevenBlack appendToListsFile MalwareDom appendToListsFile Cameleon - appendToListsFile ZeusTracker appendToListsFile DisconTrack appendToListsFile DisconAd appendToListsFile HostsFile @@ -2402,8 +2404,16 @@ FTLcheckUpdate() { if [[ ${ftlLoc} ]]; then local FTLversion FTLversion=$(/usr/bin/pihole-FTL tag) + local FTLreleaseData local FTLlatesttag - FTLlatesttag=$(curl -sI https://github.com/pi-hole/FTL/releases/latest | grep 'Location' | awk -F '/' '{print $NF}' | tr -d '\r\n') + + if ! FTLreleaseData=$(curl -sI https://github.com/pi-hole/FTL/releases/latest); then + # There was an issue while retrieving the latest version + printf " %b Failed to retrieve latest FTL release metadata" "${CROSS}" + return 3 + fi + + FTLlatesttag=$(grep 'Location' < "${FTLreleaseData}" | awk -F '/' '{print $NF}' | tr -d '\r\n') if [[ "${FTLversion}" != "${FTLlatesttag}" ]]; then return 0 diff --git a/gravity.sh b/gravity.sh index 1ad43df1..2fc26d49 100755 --- a/gravity.sh +++ b/gravity.sh @@ -30,7 +30,6 @@ whitelistFile="${piholeDir}/whitelist.txt" blacklistFile="${piholeDir}/blacklist.txt" regexFile="${piholeDir}/regex.list" adListFile="${piholeDir}/adlists.list" -auditFile="${piholeDir}/auditlog.list" localList="${piholeDir}/local.list" VPNList="/etc/openvpn/ipp.txt" @@ -127,8 +126,8 @@ database_table_from_file() { do # Only add non-empty lines if [[ -n "${domain}" ]]; then - if [[ "${table}" == "auditlist" ]]; then - # Auditlist table format + if [[ "${table}" == "domain_audit" ]]; then + # domain_audit table format (no enable or modified fields) echo "${rowid},\"${domain}\",${timestamp}" >> "${tmpFile}" else # White-, black-, and regexlist format @@ -194,7 +193,7 @@ migrate_to_database() { fi # Check if gravity database needs to be updated - upgrade_gravityDB "${gravityDBfile}" "${auditFile}" + upgrade_gravityDB "${gravityDBfile}" "${piholeDir}" } # Determine if DNS resolution is available before proceeding @@ -356,7 +355,7 @@ gravity_DownloadBlocklistFromUrl() { else printf -v port "%s" "${PIHOLE_DNS_1#*#}" fi - ip=$(dig "@${ip_addr}" -p "${port}" +short "${domain}") + ip=$(dig "@${ip_addr}" -p "${port}" +short "${domain}" | tail -1) if [[ $(echo "${url}" | awk -F '://' '{print $1}') = "https" ]]; then port=443; else port=80 diff --git a/test/fedora.Dockerfile b/test/fedora.Dockerfile index 8c27bbcc..a06fc007 100644 --- a/test/fedora.Dockerfile +++ b/test/fedora.Dockerfile @@ -1,4 +1,4 @@ -FROM fedora:29 +FROM fedora:30 ENV GITDIR /etc/.pihole ENV SCRIPTDIR /opt/pihole diff --git a/test/test_automated_install.py b/test/test_automated_install.py index 282c627d..cce11857 100644 --- a/test/test_automated_install.py +++ b/test/test_automated_install.py @@ -486,6 +486,13 @@ def test_FTL_download_aarch64_no_errors(Pihole): ''' confirms only aarch64 package is downloaded for FTL engine ''' + # mock whiptail answers and ensure installer dependencies + mock_command('whiptail', {'*': ('', '0')}, Pihole) + Pihole.run(''' + source /opt/pihole/basic-install.sh + distro_check + install_dependent_packages ${INSTALLER_DEPS[@]} + ''') download_binary = Pihole.run(''' source /opt/pihole/basic-install.sh binary="pihole-FTL-aarch64-linux-gnu" @@ -501,6 +508,13 @@ def test_FTL_download_unknown_fails_no_errors(Pihole): ''' confirms unknown binary is not downloaded for FTL engine ''' + # mock whiptail answers and ensure installer dependencies + mock_command('whiptail', {'*': ('', '0')}, Pihole) + Pihole.run(''' + source /opt/pihole/basic-install.sh + distro_check + install_dependent_packages ${INSTALLER_DEPS[@]} + ''') download_binary = Pihole.run(''' source /opt/pihole/basic-install.sh binary="pihole-FTL-mips" @@ -519,6 +533,13 @@ def test_FTL_download_binary_unset_no_errors(Pihole): ''' confirms unset binary variable does not download FTL engine ''' + # mock whiptail answers and ensure installer dependencies + mock_command('whiptail', {'*': ('', '0')}, Pihole) + Pihole.run(''' + source /opt/pihole/basic-install.sh + distro_check + install_dependent_packages ${INSTALLER_DEPS[@]} + ''') download_binary = Pihole.run(''' source /opt/pihole/basic-install.sh create_pihole_user @@ -679,3 +700,42 @@ def test_IPv6_ULA_GUA_test(Pihole): ''') expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads' assert expected_stdout in detectPlatform.stdout + + +def test_validate_ip_valid(Pihole): + ''' + Given a valid IP address, valid_ip returns success + ''' + + output = Pihole.run(''' + source /opt/pihole/basic-install.sh + valid_ip "192.168.1.1" + ''') + + assert output.rc == 0 + + +def test_validate_ip_invalid_octet(Pihole): + ''' + Given an invalid IP address (large octet), valid_ip returns an error + ''' + + output = Pihole.run(''' + source /opt/pihole/basic-install.sh + valid_ip "1092.168.1.1" + ''') + + assert output.rc == 1 + + +def test_validate_ip_invalid_letters(Pihole): + ''' + Given an invalid IP address (contains letters), valid_ip returns an error + ''' + + output = Pihole.run(''' + source /opt/pihole/basic-install.sh + valid_ip "not an IP" + ''') + + assert output.rc == 1