SHARE
TWEET

Untitled

a guest Apr 20th, 2018 175 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env bash
  2. # shellcheck disable=SC1090
  3.  
  4. # Pi-hole: A black hole for Internet advertisements
  5. # (c) 2017-2018 Pi-hole, LLC (https://pi-hole.net)
  6. # Network-wide ad blocking via your own hardware.
  7. #
  8. # Installs and Updates Pi-hole
  9. #
  10. # This file is copyright under the latest version of the EUPL.
  11. # Please see LICENSE file for your rights under this license.
  12.  
  13. # pi-hole.net/donate
  14. #
  15. # Install with this command (from your Linux machine):
  16. #
  17. # curl -sSL https://install.pi-hole.net | bash
  18.  
  19. # -e option instructs bash to immediately exit if any command [1] has a non-zero exit status
  20. # We do not want users to end up with a partially working install, so we exit the script
  21. # instead of continuing the installation with something broken
  22. set -e
  23. + set -e
  24.  
  25. ######## VARIABLES #########
  26. # For better maintainability, we store as much information that can change in variables
  27. # This allows us to make a change in one place that can propagate to all instances of the variable
  28. # These variables should all be GLOBAL variables, written in CAPS
  29. # Local variables will be in lowercase and will exist only within functions
  30. # It's still a work in progress, so you may see some variance in this guideline until it is complete
  31.  
  32. # Location for final installation log storage
  33. installLogLoc=/etc/pihole/install.log
  34. + installLogLoc=/etc/pihole/install.log
  35. # This is an important file as it contains information specific to the machine it's being installed on
  36. setupVars=/etc/pihole/setupVars.conf
  37. + setupVars=/etc/pihole/setupVars.conf
  38. # Pi-hole uses lighttpd as a Web server, and this is the config file for it
  39. # shellcheck disable=SC2034
  40. lighttpdConfig=/etc/lighttpd/lighttpd.conf
  41. + lighttpdConfig=/etc/lighttpd/lighttpd.conf
  42. # This is a file used for the colorized output
  43. coltable=/opt/pihole/COL_TABLE
  44. + coltable=/opt/pihole/COL_TABLE
  45.  
  46. # We store several other folders and
  47. webInterfaceGitUrl="https://github.com/pi-hole/AdminLTE.git"
  48. + webInterfaceGitUrl=https://github.com/pi-hole/AdminLTE.git
  49. webInterfaceDir="/var/www/html/admin"
  50. + webInterfaceDir=/var/www/html/admin
  51. piholeGitUrl="https://github.com/pi-hole/pi-hole.git"
  52. + piholeGitUrl=https://github.com/pi-hole/pi-hole.git
  53. PI_HOLE_LOCAL_REPO="/etc/.pihole"
  54. + PI_HOLE_LOCAL_REPO=/etc/.pihole
  55. # These are the names of pi-holes files, stored in an array
  56. PI_HOLE_FILES=(chronometer list piholeDebug piholeLogFlush setupLCD update version gravity uninstall webpage)
  57. + PI_HOLE_FILES=(chronometer list piholeDebug piholeLogFlush setupLCD update version gravity uninstall webpage)
  58. # This folder is where the Pi-hole scripts will be installed
  59. PI_HOLE_INSTALL_DIR="/opt/pihole"
  60. + PI_HOLE_INSTALL_DIR=/opt/pihole
  61. useUpdateVars=false
  62. + useUpdateVars=false
  63.  
  64. # Pi-hole needs an IP address; to begin, these variables are empty since we don't know what the IP is until
  65. # this script can run
  66. IPV4_ADDRESS=""
  67. + IPV4_ADDRESS=
  68. IPV6_ADDRESS=""
  69. + IPV6_ADDRESS=
  70. # By default, query logging is enabled and the dashboard is set to be installed
  71. QUERY_LOGGING=true
  72. + QUERY_LOGGING=true
  73. INSTALL_WEB=true
  74. + INSTALL_WEB=true
  75.  
  76.  
  77. # Find the rows and columns will default to 80x24 if it can not be detected
  78. screen_size=$(stty size 2>/dev/null || echo 24 80)
  79. stty size 2>/dev/null || echo 24 80
  80. ++ stty size
  81. ++ echo 24 80
  82. + screen_size='24 80'
  83. rows=$(echo "${screen_size}" | awk '{print $1}')
  84. echo "${screen_size}" | awk '{print $1}'
  85. ++ echo '24 80'
  86. ++ awk '{print $1}'
  87. + rows=24
  88. columns=$(echo "${screen_size}" | awk '{print $2}')
  89. echo "${screen_size}" | awk '{print $2}'
  90. ++ echo '24 80'
  91. ++ awk '{print $2}'
  92. + columns=80
  93.  
  94. # Divide by two so the dialogs take up half of the screen, which looks nice.
  95. r=$(( rows / 2 ))
  96. + r=12
  97. c=$(( columns / 2 ))
  98. + c=40
  99. # Unless the screen is tiny
  100. r=$(( r < 20 ? 20 : r ))
  101. + r=20
  102. c=$(( c < 70 ? 70 : c ))
  103. + c=70
  104.  
  105. ######## Undocumented Flags. Shhh ########
  106. # These are undocumented flags; some of which we can use when repairing an installation
  107. # The runUnattended flag is one example of this
  108. skipSpaceCheck=false
  109. + skipSpaceCheck=false
  110. reconfigure=false
  111. + reconfigure=false
  112. runUnattended=false
  113. + runUnattended=false
  114.  
  115. # If the color table file exists,
  116. if [[ -f "${coltable}" ]]; then
  117.   # source it
  118.   source ${coltable}
  119. # Otherwise,
  120. else
  121.   # Set these values so the installer can still run in color
  122.   COL_NC='\e[0m' # No Color
  123.   COL_LIGHT_GREEN='\e[1;32m'
  124.   COL_LIGHT_RED='\e[1;31m'
  125.   TICK="[${COL_LIGHT_GREEN}✓${COL_NC}]"
  126.   CROSS="[${COL_LIGHT_RED}✗${COL_NC}]"
  127.   INFO="[i]"
  128.   # shellcheck disable=SC2034
  129.   DONE="${COL_LIGHT_GREEN} done!${COL_NC}"
  130.   OVER="\\r\\033[K"
  131. fi
  132. + [[ -f /opt/pihole/COL_TABLE ]]
  133. + COL_NC='\e[0m'
  134. + COL_LIGHT_GREEN='\e[1;32m'
  135. + COL_LIGHT_RED='\e[1;31m'
  136. + TICK='[\e[1;32m✓\e[0m]'
  137. + CROSS='[\e[1;31m✗\e[0m]'
  138. + INFO='[i]'
  139. + DONE='\e[1;32m done!\e[0m'
  140. + OVER='\r\033[K'
  141.  
  142. # A simple function that just echoes out our logo in ASCII format
  143. # This lets users know that it is a Pi-hole, LLC product
  144. show_ascii_berry() {
  145.   echo -e "
  146.         ${COL_LIGHT_GREEN}.;;,.
  147.         .ccccc:,.
  148.          :cccclll:.      ..,,
  149.           :ccccclll.   ;ooodc
  150.            'ccll:;ll .oooodc
  151.              .;cll.;;looo:.
  152.                  ${COL_LIGHT_RED}.. ','.
  153.                 .',,,,,,'.
  154.               .',,,,,,,,,,.
  155.             .',,,,,,,,,,,,....
  156.           ....''',,,,,,,'.......
  157.         .........  ....  .........
  158.         ..........      ..........
  159.         ..........      ..........
  160.         .........  ....  .........
  161.           ........,,,,,,,'......
  162.             ....',,,,,,,,,,,,.
  163.                .',,,,,,,,,'.
  164.                 .',,,,,,'.
  165.                   ..'''.${COL_NC}
  166. "
  167. }
  168.  
  169. # Compatibility
  170. distro_check() {
  171. # If apt-get is installed, then we know it's part of the Debian family
  172. if command -v apt-get &> /dev/null; then
  173.   # Set some global variables here
  174.   # We don't set them earlier since the family might be Red Hat, so these values would be different
  175.   PKG_MANAGER="apt-get"
  176.   # A variable to store the command used to update the package cache
  177.   UPDATE_PKG_CACHE="${PKG_MANAGER} update"
  178.   # An array for something...
  179.   PKG_INSTALL=(${PKG_MANAGER} --yes --no-install-recommends install)
  180.   # grep -c will return 1 retVal on 0 matches, block this throwing the set -e with an OR TRUE
  181.   PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true"
  182.   # Some distros vary slightly so these fixes for dependencies may apply
  183.   # Debian 7 doesn't have iproute2 so if the dry run install is successful,
  184.   if ${PKG_MANAGER} install --dry-run iproute2 > /dev/null 2>&1; then
  185.     # we can install it
  186.     iproute_pkg="iproute2"
  187.   # Otherwise,
  188.   else
  189.     # use iproute
  190.     iproute_pkg="iproute"
  191.   fi
  192.   # We prefer the php metapackage if it's there
  193.   if ${PKG_MANAGER} install --dry-run php > /dev/null 2>&1; then
  194.     phpVer="php"
  195.   # If not,
  196.   else
  197.     # fall back on the php5 packages
  198.     phpVer="php5"
  199.   fi
  200.   # We also need the correct version for `php-sqlite` (which differs across distros)
  201.   if ${PKG_MANAGER} install --dry-run ${phpVer}-sqlite3 > /dev/null 2>&1; then
  202.     phpSqlite="sqlite3"
  203.   else
  204.     phpSqlite="sqlite"
  205.   fi
  206.   # Since our install script is so large, we need several other programs to successfuly get a machine provisioned
  207.   # These programs are stored in an array so they can be looped through later
  208.   INSTALLER_DEPS=(apt-utils dialog debconf dhcpcd5 git ${iproute_pkg} whiptail)
  209.   # Pi-hole itself has several dependencies that also need to be installed
  210.   PIHOLE_DEPS=(bc cron curl dnsmasq dnsutils iputils-ping lsof netcat sudo unzip wget idn2 sqlite3)
  211.   # The Web dashboard has some that also need to be installed
  212.   # It's useful to separate the two since our repos are also setup as "Core" code and "Web" code
  213.   PIHOLE_WEB_DEPS=(lighttpd ${phpVer}-common ${phpVer}-cgi ${phpVer}-${phpSqlite})
  214.   # The Web server user,
  215.   LIGHTTPD_USER="www-data"
  216.   # group,
  217.   LIGHTTPD_GROUP="www-data"
  218.   # and config file
  219.   LIGHTTPD_CFG="lighttpd.conf.debian"
  220.   # The DNS server user
  221.   DNSMASQ_USER="dnsmasq"
  222.  
  223.   # A function to check...
  224.   test_dpkg_lock() {
  225.       # An iterator used for counting loop iterations
  226.       i=0
  227.       # fuser is a program to show which processes use the named files, sockets, or filesystems
  228.       # So while the command is true
  229.       while fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do
  230.         # Wait half a second
  231.         sleep 0.5
  232.         # and increase the iterator
  233.         ((i=i+1))
  234.       done
  235.       # Always return success, since we only return if there is no
  236.       # lock (anymore)
  237.       return 0
  238.     }
  239.  
  240. # If apt-get is not found, check for rpm to see if it's a Red Hat family OS
  241. elif command -v rpm &> /dev/null; then
  242.   # Then check if dnf or yum is the package manager
  243.   if command -v dnf &> /dev/null; then
  244.     PKG_MANAGER="dnf"
  245.   else
  246.     PKG_MANAGER="yum"
  247.   fi
  248.  
  249.   # Fedora and family update cache on every PKG_INSTALL call, no need for a separate update.
  250.   UPDATE_PKG_CACHE=":"
  251.   PKG_INSTALL=(${PKG_MANAGER} install -y)
  252.   PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l"
  253.   INSTALLER_DEPS=(dialog git iproute net-tools newt procps-ng)
  254.   PIHOLE_DEPS=(bc bind-utils cronie curl dnsmasq findutils nmap-ncat sudo unzip wget libidn2 psmisc)
  255.   PIHOLE_WEB_DEPS=(lighttpd lighttpd-fastcgi php php-common php-cli php-pdo)
  256.   # EPEL (https://fedoraproject.org/wiki/EPEL) is required for lighttpd on CentOS
  257.   if grep -qi 'centos' /etc/redhat-release; then
  258.     INSTALLER_DEPS=("${INSTALLER_DEPS[@]}" "epel-release");
  259.   fi
  260.     LIGHTTPD_USER="lighttpd"
  261.     LIGHTTPD_GROUP="lighttpd"
  262.     LIGHTTPD_CFG="lighttpd.conf.fedora"
  263.     DNSMASQ_USER="nobody"
  264.  
  265. # If neither apt-get or rmp/dnf are found
  266. else
  267.   # it's not an OS we can support,
  268.   echo -e "  ${CROSS} OS distribution not supported"
  269.   # so exit the installer
  270.   exit
  271. fi
  272. }
  273.  
  274. # A function for checking if a folder is a git repository
  275. is_repo() {
  276.   # Use a named, local variable instead of the vague $1, which is the first arguement passed to this function
  277.   # These local variables should always be lowercase
  278.   local directory="${1}"
  279.   # A local variable for the current directory
  280.   local curdir
  281.   # A variable to store the return code
  282.   local rc
  283.   # Assign the current directory variable by using pwd
  284.   curdir="${PWD}"
  285.   # If the first argument passed to this function is a directory,
  286.   if [[ -d "${directory}" ]]; then
  287.     # move into the directory
  288.     cd "${directory}"
  289.     # Use git to check if the folder is a repo
  290.     # git -C is not used here to support git versions older than 1.8.4
  291.     git status --short &> /dev/null || rc=$?
  292.   # If the command was not successful,
  293.   else
  294.     # Set a non-zero return code if directory does not exist
  295.     rc=1
  296.   fi
  297.   # Move back into the directory the user started in
  298.   cd "${curdir}"
  299.   # Return the code; if one is not set, return 0
  300.   return "${rc:-0}"
  301. }
  302.  
  303. # A function to clone a repo
  304. make_repo() {
  305.   # Set named variables for better readability
  306.   local directory="${1}"
  307.   local remoteRepo="${2}"
  308.   # The message to display when this function is running
  309.   str="Clone ${remoteRepo} into ${directory}"
  310.   # Display the message and use the color table to preface the message with an "info" indicator
  311.   echo -ne "  ${INFO} ${str}..."
  312.   # If the directory exists,
  313.   if [[ -d "${directory}" ]]; then
  314.     # delete everything in it so git can clone into it
  315.     rm -rf "${directory}"
  316.   fi
  317.   # Clone the repo and return the return code from this command
  318.   git clone -q --depth 1 "${remoteRepo}" "${directory}" &> /dev/null || return $?
  319.   # Show a colored message showing it's status
  320.   echo -e "${OVER}  ${TICK} ${str}"
  321.   # Always return 0? Not sure this is correct
  322.   return 0
  323. }
  324.  
  325. # 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
  326. update_repo() {
  327.   # Use named, local variables
  328.   # As you can see, these are the same variable names used in the last function,
  329.   # but since they are local, their scope does not go beyond this function
  330.   # This helps prevent the wrong value from being assigned if you were to set the variable as a GLOBAL one
  331.   local directory="${1}"
  332.   local curdir
  333.  
  334.   # A variable to store the message we want to display;
  335.   # Again, it's useful to store these in variables in case we need to reuse or change the message;
  336.   # we only need to make one change here
  337.   local str="Update repo in ${1}"
  338.  
  339.   # Make sure we know what directory we are in so we can move back into it
  340.   curdir="${PWD}"
  341.   # Move into the directory that was passed as an argument
  342.   cd "${directory}" &> /dev/null || return 1
  343.   # Let the user know what's happening
  344.   echo -ne "  ${INFO} ${str}..."
  345.   # Stash any local commits as they conflict with our working code
  346.   git stash --all --quiet &> /dev/null || true # Okay for stash failure
  347.   git clean --quiet --force -d || true # Okay for already clean directory
  348.   # Pull the latest commits
  349.   git pull --quiet &> /dev/null || return $?
  350.   # Show a completion message
  351.   echo -e "${OVER}  ${TICK} ${str}"
  352.   # Move back into the oiginal directory
  353.   cd "${curdir}" &> /dev/null || return 1
  354.   return 0
  355. }
  356.  
  357. # A function that combines the functions previously made
  358. getGitFiles() {
  359.   # Setup named variables for the git repos
  360.   # We need the directory
  361.   local directory="${1}"
  362.   # as well as the repo URL
  363.   local remoteRepo="${2}"
  364.   # A local varible containing the message to be displayed
  365.   local str="Check for existing repository in ${1}"
  366.   # Show the message
  367.   echo -ne "  ${INFO} ${str}..."
  368.   # Check if the directory is a repository
  369.   if is_repo "${directory}"; then
  370.     # Show that we're checking it
  371.     echo -e "${OVER}  ${TICK} ${str}"
  372.     # Update the repo, returning an error message on failure
  373.     update_repo "${directory}" || { echo -e "\\n  ${COL_LIGHT_RED}Error: Could not update local repository. Contact support.${COL_NC}"; exit 1; }
  374.   # If it's not a .git repo,
  375.   else
  376.     # Show an error
  377.     echo -e "${OVER}  ${CROSS} ${str}"
  378.     # Attempt to make the repository, showing an error on falure
  379.     make_repo "${directory}" "${remoteRepo}" || { echo -e "\\n  ${COL_LIGHT_RED}Error: Could not update local repository. Contact support.${COL_N                                                                                                                                                                            C}"; exit 1; }
  380.   fi
  381.   # echo a blank line
  382.   echo ""
  383.   # and return success?
  384.   return 0
  385. }
  386.  
  387. # Reset a repo to get rid of any local changed
  388. resetRepo() {
  389.   # Use named varibles for arguments
  390.   local directory="${1}"
  391.   # Move into the directory
  392.   cd "${directory}" &> /dev/null || return 1
  393.   # Store the message in a varible
  394.   str="Resetting repository within ${1}..."
  395.   # Show the message
  396.   echo -ne "  ${INFO} ${str}"
  397.   # Use git to remove the local changes
  398.   git reset --hard &> /dev/null || return $?
  399.   # And show the status
  400.   echo -e "${OVER}  ${TICK} ${str}"
  401.   # Returning success anyway?
  402.   return 0
  403. }
  404.  
  405. # We need to know the IPv4 information so we can effectively setup the DNS server
  406. # Without this information, we won't know where to Pi-hole will be found
  407. find_IPv4_information() {
  408.   # Named, local variables
  409.   local route
  410.   # Find IP used to route to outside world by checking the the route to Google's public DNS server
  411.   route=$(ip route get 8.8.8.8)
  412.   # Use awk to strip out just the interface device as it is used in future commands
  413.   IPv4dev=$(awk '{for (i=1; i<=NF; i++) if ($i~/dev/) print $(i+1)}' <<< "${route}")
  414.   # Get just the IP address
  415.   IPv4bare=$(awk '{print $7}' <<< "${route}")
  416.   # Append the CIDR notation to the IP address
  417.   IPV4_ADDRESS=$(ip -o -f inet addr show | grep "${IPv4bare}" |  awk '{print $4}' | awk 'END {print}')
  418.   # Get the default gateway (the way to reach the Internet)
  419.   IPv4gw=$(awk '{print $3}' <<< "${route}")
  420.  
  421. }
  422.  
  423. # Get available interfaces that are UP
  424. get_available_interfaces() {
  425.   # There may be more than one so it's all stored in a variable
  426.   availableInterfaces=$(ip --oneline link show up | grep -v "lo" | awk '{print $2}' | cut -d':' -f1 | cut -d'@' -f1)
  427. }
  428.  
  429. # A function for displaying the dialogs the user sees when first running the installer
  430. welcomeDialogs() {
  431.   # Display the welcome dialog using an approriately sized window via the calculation conducted earlier in the script
  432.   whiptail --msgbox --backtitle "Welcome" --title "Pi-hole automated installer" "\\n\\nThis installer will transform your device into a network-w                                                                                                                                                                            ide ad blocker!" ${r} ${c}
  433.  
  434.   # Request that users donate if they enjoy the software since we all work on it in our free time
  435.   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}
  436.  
  437.   # Explain the need for a static address
  438.   whiptail --msgbox --backtitle "Initiating network interface" --title "Static IP Needed" "\\n\\nThe Pi-hole is a SERVER so it needs a STATIC IP                                                                                                                                                                             ADDRESS to function properly.
  439.  
  440. In the next section, you can choose to use your current network settings (DHCP) or to manually edit them." ${r} ${c}
  441. }
  442.  
  443. # We need to make sure there is enough space before installing, so there is a function to check this
  444. verifyFreeDiskSpace() {
  445.  
  446.   # 50MB is the minimum space needed (45MB install (includes web admin bootstrap/jquery libraries etc) + 5MB one day of logs.)
  447.   # - Fourdee: Local ensures the variable is only created, and accessible within this function/void. Generally considered a "good" coding practic                                                                                                                                                                            e for non-global variables.
  448.   local str="Disk space check"
  449.   # Reqired space in KB
  450.   local required_free_kilobytes=51200
  451.   # Calculate existing free space on this machine
  452.   local existing_free_kilobytes
  453.   existing_free_kilobytes=$(df -Pk | grep -m1 '\/$' | awk '{print $4}')
  454.  
  455.   # If the existing space is not an integer,
  456.   if ! [[ "${existing_free_kilobytes}" =~ ^([0-9])+$ ]]; then
  457.     # show an error that we can't determine the free space
  458.     echo -e "  ${CROSS} ${str}
  459.       Unknown free disk space!
  460.       We were unable to determine available free disk space on this system.
  461.       You may override this check, however, it is not recommended
  462.       The option '${COL_LIGHT_RED}--i_do_not_follow_recommendations${COL_NC}' can override this
  463.       e.g: curl -L https://install.pi-hole.net | bash /dev/stdin ${COL_LIGHT_RED}<option>${COL_NC}"
  464.     # exit with an error code
  465.     exit 1
  466.   # If there is insufficient free disk space,
  467.   elif [[ "${existing_free_kilobytes}" -lt "${required_free_kilobytes}" ]]; then
  468.     # show an error message
  469.     echo -e "  ${CROSS} ${str}
  470.       Your system disk appears to only have ${existing_free_kilobytes} KB free
  471.       It is recommended to have a minimum of ${required_free_kilobytes} KB to run the Pi-hole"
  472.     # if the vcgencmd command exists,
  473.     if command -v vcgencmd &> /dev/null; then
  474.       # it's probably a Raspbian install, so show a message about expanding the filesystem
  475.       echo "      If this is a new install you may need to expand your disk
  476.       Run 'sudo raspi-config', and choose the 'expand file system' option
  477.       After rebooting, run this installation again
  478.       e.g: curl -L https://install.pi-hole.net | bash"
  479.     fi
  480.     # Show there is not enough free space
  481.     echo -e "\\n      ${COL_LIGHT_RED}Insufficient free space, exiting...${COL_NC}"
  482.     # and exit with an error
  483.     exit 1
  484.   # Otherwise,
  485.   else
  486.     # Show that we're running a disk space check
  487.     echo -e "  ${TICK} ${str}"
  488.   fi
  489. }
  490.  
  491. # A function that let's the user pick an interface to use with Pi-hole
  492. chooseInterface() {
  493.   # Turn the available interfaces into an array so it can be used with a whiptail dialog
  494.   local interfacesArray=()
  495.   # Number of available interfaces
  496.   local interfaceCount
  497.   # Whiptail variable storage
  498.   local chooseInterfaceCmd
  499.   # Temporary Whiptail options storage
  500.   local chooseInterfaceOptions
  501.   # Loop sentinel variable
  502.   local firstLoop=1
  503.  
  504.   # Find out how many interfaces are available to choose from
  505.   interfaceCount=$(echo "${availableInterfaces}" | wc -l)
  506.  
  507.   # If there is one interface,
  508.   if [[ "${interfaceCount}" -eq 1 ]]; then
  509.       # Set it as the interface to use since there is no other option
  510.       PIHOLE_INTERFACE="${availableInterfaces}"
  511.   # Otherwise,
  512.   else
  513.       # While reading through the available interfaces
  514.       while read -r line; do
  515.         # use a variable to set the option as OFF to begin with
  516.         mode="OFF"
  517.         # If it's the first loop,
  518.         if [[ "${firstLoop}" -eq 1 ]]; then
  519.           # set this as the interface to use (ON)
  520.           firstLoop=0
  521.           mode="ON"
  522.         fi
  523.         # Put all these interfaces into an array
  524.         interfacesArray+=("${line}" "available" "${mode}")
  525.       # Feed the available interfaces into this while loop
  526.       done <<< "${availableInterfaces}"
  527.       # The whiptail command that will be run, stored in a variable
  528.       chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to select)" ${r} ${c} ${interfaceCount})
  529.       # Now run the command using the interfaces saved into the array
  530.       chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) || \
  531.       # If the user chooses Canel, exit
  532.       { echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
  533.       # For each interface
  534.       for desiredInterface in ${chooseInterfaceOptions}; do
  535.         # Set the one the user selected as the interface to use
  536.         PIHOLE_INTERFACE=${desiredInterface}
  537.         # and show this information to the user
  538.         echo -e "  ${INFO} Using interface: $PIHOLE_INTERFACE"
  539.       done
  540.   fi
  541. }
  542.  
  543. # This lets us prefer ULA addresses over GUA
  544. # This caused problems for some users when their ISP changed their IPv6 addresses
  545. # See https://github.com/pi-hole/pi-hole/issues/1473#issuecomment-301745953
  546. testIPv6() {
  547.   # first will contain fda2 (ULA)
  548.   first="$(cut -f1 -d":" <<< "$1")"
  549.   # value1 will contain 253 which is the decimal value corresponding to 0xfd
  550.   value1=$(( (0x$first)/256 ))
  551.   # will contain 162 which is the decimal value corresponding to 0xa2
  552.   value2=$(( (0x$first)%256 ))
  553.   # the ULA test is testing for fc00::/7 according to RFC 4193
  554.   if (( (value1&254)==252 )); then
  555.     echo "ULA"
  556.   fi
  557.   # the GUA test is testing for 2000::/3 according to RFC 4291
  558.   if (( (value1&112)==32 )); then
  559.     echo "GUA"
  560.   fi
  561.   # the LL test is testing for fe80::/10 according to RFC 4193
  562.   if (( (value1)==254 )) && (( (value2&192)==128 )); then
  563.     echo "Link-local"
  564.   fi
  565. }
  566.  
  567. # A dialog for showing the user about IPv6 blocking
  568. useIPv6dialog() {
  569.   # Determine the IPv6 address used for blocking
  570.   IPV6_ADDRESSES=($(ip -6 address | grep 'scope global' | awk '{print $2}'))
  571.  
  572.   # For each address in the array above, determine the type of IPv6 address it is
  573.   for i in "${IPV6_ADDRESSES[@]}"; do
  574.     # Check if it's ULA, GUA, or LL by using the function created earlier
  575.     result=$(testIPv6 "$i")
  576.     # If it's a ULA address, use it and store it as a global variable
  577.     [[ "${result}" == "ULA" ]] && ULA_ADDRESS="${i%/*}"
  578.     # If it's a GUA address, we can still use it si store it as a global variable
  579.     [[ "${result}" == "GUA" ]] && GUA_ADDRESS="${i%/*}"
  580.   done
  581.  
  582.   # Determine which address to be used: Prefer ULA over GUA or don't use any if none found
  583.   # If the ULA_ADDRESS contains a value,
  584.   if [[ ! -z "${ULA_ADDRESS}" ]]; then
  585.     # set the IPv6 address to the ULA address
  586.     IPV6_ADDRESS="${ULA_ADDRESS}"
  587.     # Show this info to the user
  588.     echo -e "  ${INFO} Found IPv6 ULA address, using it for blocking IPv6 ads"
  589.   # Otherwise, if the GUA_ADDRESS has a value,
  590.   elif [[ ! -z "${GUA_ADDRESS}" ]]; then
  591.     # Let the user know
  592.     echo -e "  ${INFO} Found IPv6 GUA address, using it for blocking IPv6 ads"
  593.     # And assign it to the global variable
  594.     IPV6_ADDRESS="${GUA_ADDRESS}"
  595.   # If none of those work,
  596.   else
  597.     # explain that IPv6 blocking will not be used
  598.     echo -e "  ${INFO} Unable to find IPv6 ULA/GUA address, IPv6 adblocking will not be enabled"
  599.     # So set the variable to be empty
  600.     IPV6_ADDRESS=""
  601.   fi
  602.  
  603.   # If the IPV6_ADDRESS contains a value
  604.   if [[ ! -z "${IPV6_ADDRESS}" ]]; then
  605.     # Display that IPv6 is supported and will be used
  606.     whiptail --msgbox --backtitle "IPv6..." --title "IPv6 Supported" "$IPV6_ADDRESS will be used to block ads." ${r} ${c}
  607.   fi
  608. }
  609.  
  610. # A function to check if we should use IPv4 and/or IPv6 for blocking ads
  611. use4andor6() {
  612.   # Named local variables
  613.   local useIPv4
  614.   local useIPv6
  615.   # Let use select IPv4 and/or IPv6 via a checklist
  616.   cmd=(whiptail --separate-output --checklist "Select Protocols (press space to select)" ${r} ${c} 2)
  617.   # In an array, show the options available:
  618.   # IPv4 (on by default)
  619.   options=(IPv4 "Block ads over IPv4" on
  620.   # or IPv6 (on by default if available)
  621.   IPv6 "Block ads over IPv6" on)
  622.   # In a variable, show the choices available; exit if Cancel is selected
  623.   choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) || { echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1;                                                                                                                                                                             }
  624.   # For each choice available,
  625.   for choice in ${choices}
  626.   do
  627.     # Set the values to true
  628.     case ${choice} in
  629.     IPv4  )   useIPv4=true;;
  630.     IPv6  )   useIPv6=true;;
  631.     esac
  632.   done
  633.   # If IPv4 is to be used,
  634.   if [[ "${useIPv4}" ]]; then
  635.     # Run our function to get the information we need
  636.     find_IPv4_information
  637.     getStaticIPv4Settings
  638.     setStaticIPv4
  639.   fi
  640.   # If IPv6 is to be used,
  641.   if [[ "${useIPv6}" ]]; then
  642.     # Run our function to get this information
  643.     useIPv6dialog
  644.   fi
  645.   # Echo the information to the user
  646.     echo -e "  ${INFO} IPv4 address: ${IPV4_ADDRESS}"
  647.     echo -e "  ${INFO} IPv6 address: ${IPV6_ADDRESS}"
  648.   # If neither protocol is selected,
  649.   if [[ ! "${useIPv4}" ]] && [[ ! "${useIPv6}" ]]; then
  650.     # Show an error in red
  651.     echo -e "  ${COL_LIGHT_RED}Error: Neither IPv4 or IPv6 selected${COL_NC}"
  652.     # and exit with an error
  653.     exit 1
  654.   fi
  655. }
  656.  
  657. #
  658. getStaticIPv4Settings() {
  659.   # Local, named variables
  660.   local ipSettingsCorrect
  661.   # Ask if the user wants to use DHCP settings as their static IP
  662.   # This is useful for users that are using DHCP reservations; then we can just use the information gathered via our functions
  663.   if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Do you want to use your current network settings a                                                                                                                                                                            s a static address?
  664.           IP address:    ${IPV4_ADDRESS}
  665.           Gateway:       ${IPv4gw}" ${r} ${c}; then
  666.     # If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
  667.     whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict" "It is possible your router could still try to assign this IP to a                                                                                                                                                                             device, which would cause a conflict.  But in most cases the router is smart enough to not do that.
  668. If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
  669. It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address." ${r} ${c}
  670.   # Nothing else to do since the variables are already set above
  671.   else
  672.     # Otherwise, we need to ask the user to input their desired settings.
  673.     # Start by getting the IPv4 address (pre-filling it with info gathered from DHCP)
  674.     # Start a loop to let the user enter their information with the chance to go back and edit it if necessary
  675.     until [[ "${ipSettingsCorrect}" = True ]]; do
  676.  
  677.       # Ask for the IPv4 address
  678.       IPV4_ADDRESS=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 address" --inputbox "Enter your desired IPv4 address" ${r                                                                                                                                                                            } ${c} "${IPV4_ADDRESS}" 3>&1 1>&2 2>&3) || \
  679.       # Cancelling IPv4 settings window
  680.       { ipSettingsCorrect=False; echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
  681.       echo -e "  ${INFO} Your static IPv4 address: ${IPV4_ADDRESS}"
  682.  
  683.       # Ask for the gateway
  684.       IPv4gw=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 gateway (router)" --inputbox "Enter your desired IPv4 default g                                                                                                                                                                            ateway" ${r} ${c} "${IPv4gw}" 3>&1 1>&2 2>&3) || \
  685.       # Cancelling gateway settings window
  686.       { ipSettingsCorrect=False; echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
  687.       echo -e "  ${INFO} Your static IPv4 gateway: ${IPv4gw}"
  688.  
  689.       # Give the user a chance to review their settings before moving on
  690.       if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Are these settings correct?
  691.         IP address: ${IPV4_ADDRESS}
  692.         Gateway:    ${IPv4gw}" ${r} ${c}; then
  693.         # After that's done, the loop ends and we move on
  694.         ipSettingsCorrect=True
  695.         else
  696.         # If the settings are wrong, the loop continues
  697.         ipSettingsCorrect=False
  698.       fi
  699.     done
  700.     # End the if statement for DHCP vs. static
  701.   fi
  702. }
  703.  
  704. # dhcpcd is very annoying,
  705. setDHCPCD() {
  706.   # but we can append these lines to dhcpcd.conf to enable a static IP
  707.   echo "interface ${PIHOLE_INTERFACE}
  708.   static ip_address=${IPV4_ADDRESS}
  709.   static routers=${IPv4gw}
  710.   static domain_name_servers=127.0.0.1" | tee -a /etc/dhcpcd.conf >/dev/null
  711. }
  712.  
  713. setStaticIPv4() {
  714.   # Local, named variables
  715.   local IFCFG_FILE
  716.   local IPADDR
  717.   local CIDR
  718.   # For the Debian family, if dhcpcd.conf exists,
  719.   if [[ -f "/etc/dhcpcd.conf" ]]; then
  720.     # check if the IP is already in the file
  721.     if grep -q "${IPV4_ADDRESS}" /etc/dhcpcd.conf; then
  722.       echo -e "  ${INFO} Static IP already configured"
  723.     # If it's not,
  724.     else
  725.       # set it using our function
  726.       setDHCPCD
  727.       # Then use the ip command to immediately set the new address
  728.       ip addr replace dev "${PIHOLE_INTERFACE}" "${IPV4_ADDRESS}"
  729.       # Also give a warning that the user may need to reboot their system
  730.       echo -e "  ${TICK} Set IP address to ${IPV4_ADDRESS%/*}
  731.       You may need to restart after the install is complete"
  732.     fi
  733.   # If it's not Debian, check if it's the Fedora family by checking for the file below
  734.   elif [[ -f "/etc/sysconfig/network-scripts/ifcfg-${PIHOLE_INTERFACE}" ]];then
  735.     # If it exists,
  736.     IFCFG_FILE=/etc/sysconfig/network-scripts/ifcfg-${PIHOLE_INTERFACE}
  737.     # check if the desired IP is already set
  738.     if grep -q "${IPV4_ADDRESS}" "${IFCFG_FILE}"; then
  739.       echo -e "  ${INFO} Static IP already configured"
  740.     # Otherwise,
  741.     else
  742.       # Put the IP in variables without the CIDR notation
  743.       IPADDR=$(echo "${IPV4_ADDRESS}" | cut -f1 -d/)
  744.       CIDR=$(echo "${IPV4_ADDRESS}" | cut -f2 -d/)
  745.       # Backup existing interface configuration:
  746.       cp "${IFCFG_FILE}" "${IFCFG_FILE}".pihole.orig
  747.       # Build Interface configuration file using the GLOBAL variables we have
  748.       {
  749.         echo "# Configured via Pi-hole installer"
  750.         echo "DEVICE=$PIHOLE_INTERFACE"
  751.         echo "BOOTPROTO=none"
  752.         echo "ONBOOT=yes"
  753.         echo "IPADDR=$IPADDR"
  754.         echo "PREFIX=$CIDR"
  755.         echo "GATEWAY=$IPv4gw"
  756.         echo "DNS1=$PIHOLE_DNS_1"
  757.         echo "DNS2=$PIHOLE_DNS_2"
  758.         echo "USERCTL=no"
  759.       }> "${IFCFG_FILE}"
  760.       # Use ip to immediately set the new address
  761.       ip addr replace dev "${PIHOLE_INTERFACE}" "${IPV4_ADDRESS}"
  762.       # If NetworkMangler command line interface exists and ready to mangle,
  763.       if command -v nmcli &> /dev/null && nmcli general status &> /dev/null; then
  764.         # Tell NetworkManagler to read our new sysconfig file
  765.         nmcli con load "${IFCFG_FILE}" > /dev/null
  766.       fi
  767.       # Show a warning that the user may need to restart
  768.       echo -e "  ${TICK} Set IP address to ${IPV4_ADDRESS%/*}
  769.       You may need to restart after the install is complete"
  770.     fi
  771.   # If all that fails,
  772.   else
  773.     # show an error and exit
  774.     echo -e "  ${INFO} Warning: Unable to locate configuration file to set static IPv4 address"
  775.     exit 1
  776.   fi
  777. }
  778.  
  779. # Check an IP address to see if it is a valid one
  780. valid_ip() {
  781.   # Local, named variables
  782.   local ip=${1}
  783.   local stat=1
  784.  
  785.   # If the IP matches the format xxx.xxx.xxx.xxx,
  786.   if [[ "${ip}" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
  787.     # Save the old Interfal Field Separator in a variable
  788.     OIFS=$IFS
  789.     # and set the new one to a dot (period)
  790.     IFS='.'
  791.     # Put the IP into an array
  792.     ip=(${ip})
  793.     # Restore the IFS to what it was
  794.     IFS=${OIFS}
  795.     ## Evaluate each octet by checking if it's less than or equal to 255 (the max for each octet)
  796.     [[ "${ip[0]}" -le 255 && "${ip[1]}" -le 255 \
  797.     && "${ip[2]}" -le 255 && "${ip[3]}" -le 255 ]]
  798.     # Save the exit code
  799.     stat=$?
  800.   fi
  801.   # Return the exit code
  802.   return ${stat}
  803. }
  804.  
  805. # A function to choose the upstream DNS provider(s)
  806. setDNS() {
  807.   # Local, named variables
  808.   local DNSSettingsCorrect
  809.  
  810.   # In an array, list the available upstream providers
  811.   DNSChooseOptions=(Google ""
  812.       OpenDNS ""
  813.       Level3 ""
  814.       Norton ""
  815.       Comodo ""
  816.       DNSWatch ""
  817.       Quad9 ""
  818.       FamilyShield ""
  819.       Custom "")
  820.   # In a whiptail dialog, show the options
  821.   DNSchoices=$(whiptail --separate-output --menu "Select Upstream DNS Provider. To use your own, select Custom." ${r} ${c} 7 \
  822.     "${DNSChooseOptions[@]}" 2>&1 >/dev/tty) || \
  823.     # exit if Cancel is selected
  824.     { echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
  825.  
  826.   # Display the selection
  827.   echo -ne "  ${INFO} Using "
  828.   # Depending on the user's choice, set the GLOBAl variables to the IP of the respective provider
  829.   case ${DNSchoices} in
  830.     Google)
  831.       echo "Google DNS servers"
  832.       PIHOLE_DNS_1="8.8.8.8"
  833.       PIHOLE_DNS_2="8.8.4.4"
  834.       ;;
  835.     OpenDNS)
  836.       echo "OpenDNS servers"
  837.       PIHOLE_DNS_1="208.67.222.222"
  838.       PIHOLE_DNS_2="208.67.220.220"
  839.       ;;
  840.     Level3)
  841.       echo "Level3 servers"
  842.       PIHOLE_DNS_1="4.2.2.1"
  843.       PIHOLE_DNS_2="4.2.2.2"
  844.       ;;
  845.     Norton)
  846.       echo "Norton ConnectSafe servers"
  847.       PIHOLE_DNS_1="199.85.126.10"
  848.       PIHOLE_DNS_2="199.85.127.10"
  849.       ;;
  850.     Comodo)
  851.       echo "Comodo Secure servers"
  852.       PIHOLE_DNS_1="8.26.56.26"
  853.       PIHOLE_DNS_2="8.20.247.20"
  854.       ;;
  855.     DNSWatch)
  856.       echo "DNS.WATCH servers"
  857.       PIHOLE_DNS_1="84.200.69.80"
  858.       PIHOLE_DNS_2="84.200.70.40"
  859.       ;;
  860.     Quad9)
  861.       echo "Quad9 servers"
  862.       PIHOLE_DNS_1="9.9.9.9"
  863.       PIHOLE_DNS_2="149.112.112.112"
  864.       ;;
  865.     FamilyShield)
  866.       echo "FamilyShield servers"
  867.       PIHOLE_DNS_1="208.67.222.123"
  868.       PIHOLE_DNS_2="208.67.220.123"
  869.       ;;
  870.     Custom)
  871.       # Until the DNS settings are selected,
  872.       until [[ "${DNSSettingsCorrect}" = True ]]; do
  873.       #
  874.       strInvalid="Invalid"
  875.       # If the first
  876.       if [[ ! "${PIHOLE_DNS_1}" ]]; then
  877.         # and second upstream servers do not exist
  878.         if [[ ! "${PIHOLE_DNS_2}" ]]; then
  879.           #
  880.           prePopulate=""
  881.         # Otherwise,
  882.         else
  883.           #
  884.           prePopulate=", ${PIHOLE_DNS_2}"
  885.         fi
  886.       #
  887.       elif  [[ "${PIHOLE_DNS_1}" ]] && [[ ! "${PIHOLE_DNS_2}" ]]; then
  888.         #
  889.         prePopulate="${PIHOLE_DNS_1}"
  890.       #
  891.       elif [[ "${PIHOLE_DNS_1}" ]] && [[ "${PIHOLE_DNS_2}" ]]; then
  892.         #
  893.         prePopulate="${PIHOLE_DNS_1}, ${PIHOLE_DNS_2}"
  894.       fi
  895.  
  896.       # Dialog for the user to enter custom upstream servers
  897.       piholeDNS=$(whiptail --backtitle "Specify Upstream DNS Provider(s)"  --inputbox "Enter your desired upstream DNS provider(s), seperated by                                                                                                                                                                             a comma.\\n\\nFor example '8.8.8.8, 8.8.4.4'" ${r} ${c} "${prePopulate}" 3>&1 1>&2 2>&3) || \
  898.       { echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
  899.       #
  900.       PIHOLE_DNS_1=$(echo "${piholeDNS}" | sed 's/[, \t]\+/,/g' | awk -F, '{print$1}')
  901.       PIHOLE_DNS_2=$(echo "${piholeDNS}" | sed 's/[, \t]\+/,/g' | awk -F, '{print$2}')
  902.       # If the IP is valid,
  903.       if ! valid_ip "${PIHOLE_DNS_1}" || [[ ! "${PIHOLE_DNS_1}" ]]; then
  904.         # store it in the variable so we can use it
  905.         PIHOLE_DNS_1=${strInvalid}
  906.       fi
  907.       # Do the same for the secondary server
  908.       if ! valid_ip "${PIHOLE_DNS_2}" && [[ "${PIHOLE_DNS_2}" ]]; then
  909.         PIHOLE_DNS_2=${strInvalid}
  910.       fi
  911.       # If either of the DNS servers are invalid,
  912.       if [[ "${PIHOLE_DNS_1}" == "${strInvalid}" ]] || [[ "${PIHOLE_DNS_2}" == "${strInvalid}" ]]; then
  913.         # explain this to the user
  914.         whiptail --msgbox --backtitle "Invalid IP" --title "Invalid IP" "One or both entered IP addresses were invalid. Please try again.\\n\\n                                                                                                                                                                                DNS Server 1:   $PIHOLE_DNS_1\\n    DNS Server 2:   ${PIHOLE_DNS_2}" ${r} ${c}
  915.         # and set the variables back to nothing
  916.         if [[ "${PIHOLE_DNS_1}" == "${strInvalid}" ]]; then
  917.           PIHOLE_DNS_1=""
  918.         fi
  919.         if [[ "${PIHOLE_DNS_2}" == "${strInvalid}" ]]; then
  920.           PIHOLE_DNS_2=""
  921.         fi
  922.         # Since the settings will not work, stay in the loop
  923.         DNSSettingsCorrect=False
  924.       # Othwerise,
  925.       else
  926.         # Show the settings
  927.         if (whiptail --backtitle "Specify Upstream DNS Provider(s)" --title "Upstream DNS Provider(s)" --yesno "Are these settings correct?\\n                                                                                                                                                                                DNS Server 1:   $PIHOLE_DNS_1\\n    DNS Server 2:   ${PIHOLE_DNS_2}" ${r} ${c}); then
  928.         # and break from the loop since the servers are vaid
  929.         DNSSettingsCorrect=True
  930.       # Otherwise,
  931.       else
  932.         # If the settings are wrong, the loop continues
  933.         DNSSettingsCorrect=False
  934.         fi
  935.       fi
  936.       done
  937.       ;;
  938.   esac
  939. }
  940.  
  941. # Allow the user to enable/disable logging
  942. setLogging() {
  943.   # Local, named variables
  944.   local LogToggleCommand
  945.   local LogChooseOptions
  946.   local LogChoices
  947.  
  948.   # Ask if the user wants to log queries
  949.   LogToggleCommand=(whiptail --separate-output --radiolist "Do you want to log queries?\\n (Disabling will render graphs on the Admin page useles                                                                                                                                                                            s):" ${r} ${c} 6)
  950.   # The default selection is on
  951.   LogChooseOptions=("On (Recommended)" "" on
  952.       Off "" off)
  953.   # Get the user's choice
  954.   LogChoices=$("${LogToggleCommand[@]}" "${LogChooseOptions[@]}" 2>&1 >/dev/tty) || (echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting inst                                                                                                                                                                            aller${COL_NC}" && exit 1)
  955.     case ${LogChoices} in
  956.       # If it's on
  957.       "On (Recommended)")
  958.         echo -e "  ${INFO} Logging On."
  959.         # Set the GLOBAL variable to true so we know what they selected
  960.         QUERY_LOGGING=true
  961.         ;;
  962.       # Othwerise, it's off,
  963.       Off)
  964.         echo -e "  ${INFO} Logging Off."
  965.         # So set it to false
  966.         QUERY_LOGGING=false
  967.         ;;
  968.     esac
  969. }
  970.  
  971. # Function to ask the user if they want to install the dashboard
  972. setAdminFlag() {
  973.   # Local, named variables
  974.   local WebToggleCommand
  975.   local WebChooseOptions
  976.   local WebChoices
  977.  
  978.   # Similar to the logging function, ask what the user wants
  979.   WebToggleCommand=(whiptail --separate-output --radiolist "Do you wish to install the web admin interface?" ${r} ${c} 6)
  980.   # with the default being enabled
  981.   WebChooseOptions=("On (Recommended)" "" on
  982.       Off "" off)
  983.   WebChoices=$("${WebToggleCommand[@]}" "${WebChooseOptions[@]}" 2>&1 >/dev/tty) || (echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting inst                                                                                                                                                                            aller${COL_NC}" && exit 1)
  984.     # Depending on their choice
  985.     case ${WebChoices} in
  986.       "On (Recommended)")
  987.         echo -e "  ${INFO} Web Interface On"
  988.         # Set it to true
  989.         INSTALL_WEB=true
  990.         ;;
  991.       Off)
  992.         echo -e "  ${INFO} Web Interface Off"
  993.         # or false
  994.         INSTALL_WEB=false
  995.         ;;
  996.     esac
  997. }
  998.  
  999. # Check if /etc/dnsmasq.conf is from pi-hole.  If so replace with an original and install new in .d directory
  1000. version_check_dnsmasq() {
  1001.   # Local, named variables
  1002.   local dnsmasq_conf="/etc/dnsmasq.conf"
  1003.   local dnsmasq_conf_orig="/etc/dnsmasq.conf.orig"
  1004.   local dnsmasq_pihole_id_string="addn-hosts=/etc/pihole/gravity.list"
  1005.   local dnsmasq_original_config="${PI_HOLE_LOCAL_REPO}/advanced/dnsmasq.conf.original"
  1006.   local dnsmasq_pihole_01_snippet="${PI_HOLE_LOCAL_REPO}/advanced/01-pihole.conf"
  1007.   local dnsmasq_pihole_01_location="/etc/dnsmasq.d/01-pihole.conf"
  1008.  
  1009.   # If the dnsmasq config file exists
  1010.   if [[ -f "${dnsmasq_conf}" ]]; then
  1011.     echo -ne "  ${INFO} Existing dnsmasq.conf found..."
  1012.     # If gravity.list is found within this file, we presume it's from older versions on Pi-hole,
  1013.     if grep -q ${dnsmasq_pihole_id_string} ${dnsmasq_conf}; then
  1014.       echo " it is from a previous Pi-hole install."
  1015.       echo -ne "  ${INFO} Backing up dnsmasq.conf to dnsmasq.conf.orig..."
  1016.       # so backup the original file
  1017.       mv -f ${dnsmasq_conf} ${dnsmasq_conf_orig}
  1018.       echo -e "${OVER}  ${TICK} Backing up dnsmasq.conf to dnsmasq.conf.orig..."
  1019.       echo -ne "  ${INFO} Restoring default dnsmasq.conf..."
  1020.       # and replace it with the default
  1021.       cp ${dnsmasq_original_config} ${dnsmasq_conf}
  1022.       echo -e "${OVER}  ${TICK} Restoring default dnsmasq.conf..."
  1023.     # Otherwise,
  1024.     else
  1025.       # Don't to anything
  1026.       echo " it is not a Pi-hole file, leaving alone!"
  1027.     fi
  1028.   else
  1029.     # If a file cannot be found,
  1030.     echo -ne "  ${INFO} No dnsmasq.conf found... restoring default dnsmasq.conf..."
  1031.     # restore the default one
  1032.     cp ${dnsmasq_original_config} ${dnsmasq_conf}
  1033.     echo -e "${OVER}  ${TICK} No dnsmasq.conf found... restoring default dnsmasq.conf..."
  1034.   fi
  1035.  
  1036.   echo -en "  ${INFO} Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf..."
  1037.   # Copy the new Pi-hole DNS config file into the dnsmasq.d directory
  1038.   cp ${dnsmasq_pihole_01_snippet} ${dnsmasq_pihole_01_location}
  1039.   echo -e "${OVER}  ${TICK} Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf"
  1040.   # Replace our placeholder values with the GLOBAL DNS variables that we populated earlier
  1041.   # First, swap in the interface to listen on
  1042.   sed -i "s/@INT@/$PIHOLE_INTERFACE/" ${dnsmasq_pihole_01_location}
  1043.   if [[ "${PIHOLE_DNS_1}" != "" ]]; then
  1044.     # Then swap in the primary DNS server
  1045.     sed -i "s/@DNS1@/$PIHOLE_DNS_1/" ${dnsmasq_pihole_01_location}
  1046.   else
  1047.     #
  1048.     sed -i '/^server=@DNS1@/d' ${dnsmasq_pihole_01_location}
  1049.   fi
  1050.   if [[ "${PIHOLE_DNS_2}" != "" ]]; then
  1051.     # Then swap in the primary DNS server
  1052.     sed -i "s/@DNS2@/$PIHOLE_DNS_2/" ${dnsmasq_pihole_01_location}
  1053.   else
  1054.     #
  1055.     sed -i '/^server=@DNS2@/d' ${dnsmasq_pihole_01_location}
  1056.   fi
  1057.  
  1058.   #
  1059.   sed -i 's/^#conf-dir=\/etc\/dnsmasq.d$/conf-dir=\/etc\/dnsmasq.d/' ${dnsmasq_conf}
  1060.  
  1061.   # If the user does not want to enable logging,
  1062.   if [[ "${QUERY_LOGGING}" == false ]] ; then
  1063.         # Disable it by commenting out the directive in the DNS config file
  1064.         sed -i 's/^log-queries/#log-queries/' ${dnsmasq_pihole_01_location}
  1065.     # Otherwise,
  1066.     else
  1067.         # enable it by uncommenting the directive in the DNS config file
  1068.         sed -i 's/^#log-queries/log-queries/' ${dnsmasq_pihole_01_location}
  1069.     fi
  1070. }
  1071.  
  1072. # Clean an existing installation to prepare for upgrade/reinstall
  1073. clean_existing() {
  1074.   # Local, named variables
  1075.   # ${1} Directory to clean
  1076.   local clean_directory="${1}"
  1077.   # Make ${2} the new one?
  1078.   shift
  1079.   # ${2} Array of files to remove
  1080.   local old_files=( "$@" )
  1081.  
  1082.   # For each script found in the old files array
  1083.   for script in "${old_files[@]}"; do
  1084.     # Remove them
  1085.     rm -f "${clean_directory}/${script}.sh"
  1086.   done
  1087. }
  1088.  
  1089. # Install the scripts from repository to their various locations
  1090. installScripts() {
  1091.   # Local, named variables
  1092.   local str="Installing scripts from ${PI_HOLE_LOCAL_REPO}"
  1093.   echo -ne "  ${INFO} ${str}..."
  1094.  
  1095.   # Clear out script files from Pi-hole scripts directory.
  1096.   clean_existing "${PI_HOLE_INSTALL_DIR}" "${PI_HOLE_FILES[@]}"
  1097.  
  1098.   # Install files from local core repository
  1099.   if is_repo "${PI_HOLE_LOCAL_REPO}"; then
  1100.     # move into the directory
  1101.     cd "${PI_HOLE_LOCAL_REPO}"
  1102.     # Install the scripts by:
  1103.     #  -o setting the owner to the user
  1104.     #  -Dm755 create all leading components of destiantion except the last, then copy the source to the destiantion and setting the permissions t                                                                                                                                                                            o 755
  1105.     #
  1106.     # This first one is the directory
  1107.     install -o "${USER}" -Dm755 -d "${PI_HOLE_INSTALL_DIR}"
  1108.     # The rest are the scripts Pi-hole needs
  1109.     install -o "${USER}" -Dm755 -t "${PI_HOLE_INSTALL_DIR}" gravity.sh
  1110.     install -o "${USER}" -Dm755 -t "${PI_HOLE_INSTALL_DIR}" ./advanced/Scripts/*.sh
  1111.     install -o "${USER}" -Dm755 -t "${PI_HOLE_INSTALL_DIR}" ./automated\ install/uninstall.sh
  1112.     install -o "${USER}" -Dm755 -t "${PI_HOLE_INSTALL_DIR}" ./advanced/Scripts/COL_TABLE
  1113.     install -o "${USER}" -Dm755 -t /usr/local/bin/ pihole
  1114.     install -Dm644 ./advanced/bash-completion/pihole /etc/bash_completion.d/pihole
  1115.     echo -e "${OVER}  ${TICK} ${str}"
  1116.  # Otherwise,
  1117.   else
  1118.     # Show an error and exit
  1119.     echo -e "${OVER}  ${CROSS} ${str}
  1120.   ${COL_LIGHT_RED}Error: Local repo ${PI_HOLE_LOCAL_REPO} not found, exiting installer${COL_NC}"
  1121.     exit 1
  1122.   fi
  1123. }
  1124.  
  1125. # Install the configs from PI_HOLE_LOCAL_REPO to their various locations
  1126. installConfigs() {
  1127.   echo ""
  1128.   echo -e "  ${INFO} Installing configs from ${PI_HOLE_LOCAL_REPO}..."
  1129.   # Make sure Pi-hole's config files are in place
  1130.   version_check_dnsmasq
  1131.  
  1132.   # If the user chose to install the dashboard,
  1133.   if [[ "${INSTALL_WEB}" == true ]]; then
  1134.     # and if the Web server conf directory does not exist,
  1135.     if [[ ! -d "/etc/lighttpd" ]]; then
  1136.       # make it
  1137.       mkdir /etc/lighttpd
  1138.       # and set the owners
  1139.       chown "${USER}":root /etc/lighttpd
  1140.     # Otherwise, if the config file already exists
  1141.     elif [[ -f "/etc/lighttpd/lighttpd.conf" ]]; then
  1142.       # back up the original
  1143.       mv /etc/lighttpd/lighttpd.conf /etc/lighttpd/lighttpd.conf.orig
  1144.     fi
  1145.     # and copy in the config file Pi-hole needs
  1146.     cp ${PI_HOLE_LOCAL_REPO}/advanced/${LIGHTTPD_CFG} /etc/lighttpd/lighttpd.conf
  1147.     # if there is a custom block page in the html/pihole directory, replace 404 handler in lighttpd config
  1148.     if [[ -f "/var/www/html/pihole/custom.php" ]]; then
  1149.       sed -i 's/^\(server\.error-handler-404\s*=\s*\).*$/\1"pihole\/custom\.php"/' /etc/lighttpd/lighttpd.conf
  1150.     fi
  1151.     # Make the directories if they do not exist and set the owners
  1152.     mkdir -p /var/run/lighttpd
  1153.     chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/run/lighttpd
  1154.     mkdir -p /var/cache/lighttpd/compress
  1155.     chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/compress
  1156.     mkdir -p /var/cache/lighttpd/uploads
  1157.     chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/uploads
  1158.   fi
  1159. }
  1160.  
  1161. stop_service() {
  1162.   # Stop service passed in as argument.
  1163.   # Can softfail, as process may not be installed when this is called
  1164.   local str="Stopping ${1} service"
  1165.   echo ""
  1166.   echo -ne "  ${INFO} ${str}..."
  1167.   if command -v systemctl &> /dev/null; then
  1168.     systemctl stop "${1}" &> /dev/null || true
  1169.   else
  1170.     service "${1}" stop &> /dev/null || true
  1171.   fi
  1172.   echo -e "${OVER}  ${TICK} ${str}..."
  1173. }
  1174.  
  1175. # Start/Restart service passed in as argument
  1176. start_service() {
  1177.   # Local, named variables
  1178.   local str="Starting ${1} service"
  1179.   echo ""
  1180.   echo -ne "  ${INFO} ${str}..."
  1181.   # If systemctl exists,
  1182.   if command -v systemctl &> /dev/null; then
  1183.     # use that to restart the service
  1184.     systemctl restart "${1}" &> /dev/null
  1185.   # Otherwise,
  1186.   else
  1187.     # fall back to the service command
  1188.     service "${1}" restart &> /dev/null
  1189.   fi
  1190.   echo -e "${OVER}  ${TICK} ${str}"
  1191. }
  1192.  
  1193. # Enable service so that it will start with next reboot
  1194. enable_service() {
  1195.   # Local, named variables
  1196.   local str="Enabling ${1} service to start on reboot"
  1197.   echo ""
  1198.   echo -ne "  ${INFO} ${str}..."
  1199.   # If systemctl exists,
  1200.   if command -v systemctl &> /dev/null; then
  1201.     # use that to enable the service
  1202.     systemctl enable "${1}" &> /dev/null
  1203.   # Othwerwise,
  1204.   else
  1205.     # use update-rc.d to accomplish this
  1206.     update-rc.d "${1}" defaults &> /dev/null
  1207.   fi
  1208.   echo -e "${OVER}  ${TICK} ${str}"
  1209. }
  1210.  
  1211. update_package_cache() {
  1212.   # Running apt-get update/upgrade with minimal output can cause some issues with
  1213.   # requiring user input (e.g password for phpmyadmin see #218)
  1214.  
  1215.   # Update package cache on apt based OSes. Do this every time since
  1216.   # it's quick and packages can be updated at any time.
  1217.  
  1218.   # Local, named variables
  1219.   local str="Update local cache of available packages"
  1220.   echo ""
  1221.   echo -ne "  ${INFO} ${str}..."
  1222.   # Create a command from the package cache variable
  1223.   if eval "${UPDATE_PKG_CACHE}" &> /dev/null; then
  1224.     echo -e "${OVER}  ${TICK} ${str}"
  1225.   # Otherwise,
  1226.   else
  1227.     # show an error and exit
  1228.     echo -e "${OVER}  ${CROSS} ${str}"
  1229.     echo -ne "  ${COL_LIGHT_RED}Error: Unable to update package cache. Please try \"${UPDATE_PKG_CACHE}\"${COL_NC}"
  1230.     return 1
  1231.   fi
  1232. }
  1233.  
  1234. # Let user know if they have outdated packages on their system and
  1235. # advise them to run a package update at soonest possible.
  1236. notify_package_updates_available() {
  1237.   # Local, named variables
  1238.   local str="Checking ${PKG_MANAGER} for upgraded packages"
  1239.   echo -ne "\\n  ${INFO} ${str}..."
  1240.   # Store the list of packages in a variable
  1241.   updatesToInstall=$(eval "${PKG_COUNT}")
  1242.  
  1243.   if [[ -d "/lib/modules/$(uname -r)" ]]; then
  1244.     #
  1245.     if [[ "${updatesToInstall}" -eq 0 ]]; then
  1246.       #
  1247.       echo -e "${OVER}  ${TICK} ${str}... up to date!"
  1248.       echo ""
  1249.     else
  1250.       #
  1251.       echo -e "${OVER}  ${TICK} ${str}... ${updatesToInstall} updates available"
  1252.       echo -e "  ${INFO} ${COL_LIGHT_GREEN}It is recommended to update your OS after installing the Pi-hole! ${COL_NC}"
  1253.       echo ""
  1254.     fi
  1255.   else
  1256.     echo -e "${OVER}  ${CROSS} ${str}
  1257.       Kernel update detected. If the install fails, please reboot and try again\\n"
  1258.   fi
  1259. }
  1260.  
  1261. # What's this doing outside of a function in the middle of nowhere?
  1262. counter=0
  1263. + counter=0
  1264.  
  1265. install_dependent_packages() {
  1266.   # Local, named variables should be used here, especially for an iterator
  1267.   # Add one to the counter
  1268.   counter=$((counter+1))
  1269.   # If it equals 1,
  1270.   if [[ "${counter}" == 1 ]]; then
  1271.     #
  1272.     echo -e "  ${INFO} Installer Dependency checks..."
  1273.   else
  1274.     #
  1275.     echo -e "  ${INFO} Main Dependency checks..."
  1276.   fi
  1277.  
  1278.   # Install packages passed in via argument array
  1279.   # No spinner - conflicts with set -e
  1280.   declare -a argArray1=("${!1}")
  1281.   declare -a installArray
  1282.  
  1283.   # Debian based package install - debconf will download the entire package list
  1284.   # so we just create an array of packages not currently installed to cut down on the
  1285.   # amount of download traffic.
  1286.   # NOTE: We may be able to use this installArray in the future to create a list of package that were
  1287.   # installed by us, and remove only the installed packages, and not the entire list.
  1288.   if command -v debconf-apt-progress &> /dev/null; then
  1289.     # For each package,
  1290.     for i in "${argArray1[@]}"; do
  1291.       echo -ne "  ${INFO} Checking for $i..."
  1292.       #
  1293.       if dpkg-query -W -f='${Status}' "${i}" 2>/dev/null | grep "ok installed" &> /dev/null; then
  1294.         #
  1295.         echo -e "${OVER}  ${TICK} Checking for $i"
  1296.       else
  1297.         #
  1298.         echo -e "${OVER}  ${INFO} Checking for $i (will be installed)"
  1299.         #
  1300.         installArray+=("${i}")
  1301.       fi
  1302.     done
  1303.     #
  1304.     if [[ "${#installArray[@]}" -gt 0 ]]; then
  1305.       #
  1306.       test_dpkg_lock
  1307.       #
  1308.       debconf-apt-progress -- "${PKG_INSTALL[@]}" "${installArray[@]}"
  1309.       return
  1310.     fi
  1311.       echo ""
  1312.       #
  1313.       return 0
  1314.   fi
  1315.  
  1316.   # Install Fedora/CentOS packages
  1317.   for i in "${argArray1[@]}"; do
  1318.     echo -ne "  ${INFO} Checking for $i..."
  1319.     #
  1320.     if ${PKG_MANAGER} -q list installed "${i}" &> /dev/null; then
  1321.       echo -e "${OVER}  ${TICK} Checking for $i"
  1322.     else
  1323.       echo -e "${OVER}  ${INFO} Checking for $i (will be installed)"
  1324.       #
  1325.       installArray+=("${i}")
  1326.     fi
  1327.   done
  1328.   #
  1329.   if [[ "${#installArray[@]}" -gt 0 ]]; then
  1330.     #
  1331.     "${PKG_INSTALL[@]}" "${installArray[@]}" &> /dev/null
  1332.     return
  1333.   fi
  1334.   echo ""
  1335.   return 0
  1336. }
  1337.  
  1338. # Create logfiles if necessary
  1339. CreateLogFile() {
  1340.   local str="Creating log and changing owner to dnsmasq"
  1341.   echo ""
  1342.   echo -ne "  ${INFO} ${str}..."
  1343.   # If the pihole log does not exist,
  1344.   if [[ ! -f "/var/log/pihole.log" ]]; then
  1345.     # Make it,
  1346.     touch /var/log/pihole.log
  1347.     # set the permissions,
  1348.     chmod 644 /var/log/pihole.log
  1349.     # and owners
  1350.     chown "${DNSMASQ_USER}":root /var/log/pihole.log
  1351.     echo -e "${OVER}  ${TICK} ${str}"
  1352.   # Otherwise,
  1353.   else
  1354.     # the file should already exist
  1355.     echo -e " ${COL_LIGHT_GREEN}log already exists!${COL_NC}"
  1356.   fi
  1357. }
  1358.  
  1359. # Install the Web interface dashboard
  1360. installPiholeWeb() {
  1361.   echo ""
  1362.   echo "  ${INFO} Installing blocking page..."
  1363.  
  1364.   local str="Creating directory for blocking page, and copying files"
  1365.   echo -ne "  ${INFO} ${str}..."
  1366.   # Install the directory
  1367.   install -d /var/www/html/pihole
  1368.   # and the blockpage
  1369.   install -D ${PI_HOLE_LOCAL_REPO}/advanced/{index,blockingpage}.* /var/www/html/pihole/
  1370.  
  1371.   # Remove superseded file
  1372.   if [[ -e "/var/www/html/pihole/index.js" ]]; then
  1373.     rm "/var/www/html/pihole/index.js"
  1374.   fi
  1375.  
  1376.   echo -e "${OVER}  ${TICK} ${str}"
  1377.  
  1378.   local str="Backing up index.lighttpd.html"
  1379.   echo -ne "  ${INFO} ${str}..."
  1380.   # If the default index file exists,
  1381.   if [[ -f "/var/www/html/index.lighttpd.html" ]]; then
  1382.     # back it up
  1383.     mv /var/www/html/index.lighttpd.html /var/www/html/index.lighttpd.orig
  1384.     echo -e "${OVER}  ${TICK} ${str}"
  1385.   # Othwerwise,
  1386.   else
  1387.     # don't do anything
  1388.     echo -e "${OVER}  ${CROSS} ${str}
  1389.       No default index.lighttpd.html file found... not backing up"
  1390.   fi
  1391.  
  1392.   # Install Sudoers file
  1393.   echo ""
  1394.   local str="Installing sudoer file"
  1395.   echo -ne "  ${INFO} ${str}..."
  1396.   # Make the .d directory if it doesn't exist
  1397.   mkdir -p /etc/sudoers.d/
  1398.   # and copy in the pihole sudoers file
  1399.   cp ${PI_HOLE_LOCAL_REPO}/advanced/pihole.sudo /etc/sudoers.d/pihole
  1400.   # Add lighttpd user (OS dependent) to sudoers file
  1401.   echo "${LIGHTTPD_USER} ALL=NOPASSWD: /usr/local/bin/pihole" >> /etc/sudoers.d/pihole
  1402.  
  1403.   # If the Web server user is lighttpd,
  1404.   if [[ "$LIGHTTPD_USER" == "lighttpd" ]]; then
  1405.     # Allow executing pihole via sudo with Fedora
  1406.     # Usually /usr/local/bin is not permitted as directory for sudoable programms
  1407.     echo "Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin" >> /etc/sudoers.d/pihole
  1408.   fi
  1409.   # Set the strict permissions on the file
  1410.   chmod 0440 /etc/sudoers.d/pihole
  1411.   echo -e "${OVER}  ${TICK} ${str}"
  1412. }
  1413.  
  1414. # Installs a cron file
  1415. installCron() {
  1416.   # Install the cron job
  1417.   local str="Installing latest Cron script"
  1418.   echo ""
  1419.   echo -ne "  ${INFO} ${str}..."
  1420.   # Copy the cron file over from the local repo
  1421.   cp ${PI_HOLE_LOCAL_REPO}/advanced/pihole.cron /etc/cron.d/pihole
  1422.   # Randomize gravity update time
  1423.   sed -i "s/59 1 /$((1 + RANDOM % 58)) $((3 + RANDOM % 2))/" /etc/cron.d/pihole
  1424.   # Randomize update checker time
  1425.   sed -i "s/59 17/$((1 + RANDOM % 58)) $((12 + RANDOM % 8))/" /etc/cron.d/pihole
  1426.   echo -e "${OVER}  ${TICK} ${str}"
  1427. }
  1428.  
  1429. # Gravity is a very important script as it aggregates all of the domains into a single HOSTS formatted list,
  1430. # which is what Pi-hole needs to begin blocking ads
  1431. runGravity() {
  1432.   echo ""
  1433.   echo -e "  ${INFO} Preparing to run gravity.sh to refresh hosts..."
  1434.   # If cached lists exist,
  1435.   if ls /etc/pihole/list* 1> /dev/null 2>&1; then
  1436.     echo -e "  ${INFO} Cleaning up previous install (preserving whitelist/blacklist)"
  1437.     # remove them
  1438.     rm /etc/pihole/list.*
  1439.   fi
  1440.   # If the default ad lists file exists,
  1441.   if [[ ! -e /etc/pihole/adlists.default ]]; then
  1442.     # copy it over from the local repo
  1443.     cp ${PI_HOLE_LOCAL_REPO}/adlists.default /etc/pihole/adlists.default
  1444.   fi
  1445.   echo -e "  ${INFO} Running gravity.sh"
  1446.   # Run gravity in the current shell
  1447.   { /opt/pihole/gravity.sh; }
  1448. }
  1449.  
  1450. # Check if the pihole user exists and create if it does not
  1451. create_pihole_user() {
  1452.   local str="Checking for user 'pihole'"
  1453.   echo -ne "  ${INFO} ${str}..."
  1454.   # If the user pihole exists,
  1455.   if id -u pihole &> /dev/null; then
  1456.     # just show a success
  1457.     echo -ne "${OVER}  ${TICK} ${str}"
  1458.   # Othwerwise,
  1459.   else
  1460.     echo -ne "${OVER}  ${CROSS} ${str}"
  1461.     local str="Creating user 'pihole'"
  1462.     echo -ne "  ${INFO} ${str}..."
  1463.     # create her with the useradd command
  1464.     useradd -r -s /usr/sbin/nologin pihole
  1465.     echo -ne "${OVER}  ${TICK} ${str}"
  1466.   fi
  1467. }
  1468.  
  1469. # Allow HTTP and DNS traffic
  1470. configureFirewall() {
  1471.   echo ""
  1472.   # If a firewall is running,
  1473.   if firewall-cmd --state &> /dev/null; then
  1474.     # ask if the user wants to install Pi-hole's default firwall rules
  1475.     whiptail --title "Firewall in use" --yesno "We have detected a running firewall\\n\\nPi-hole currently requires HTTP and DNS port access.\\n\                                                                                                                                                                            \n\\n\\nInstall Pi-hole default firewall rules?" ${r} ${c} || \
  1476.     { echo -e "  ${INFO} Not installing firewall rulesets."; return 0; }
  1477.     echo -e "  ${TICK} Configuring FirewallD for httpd and dnsmasq"
  1478.     # Allow HTTP and DNS traffice
  1479.     firewall-cmd --permanent --add-service=http --add-service=dns
  1480.     # Reload the firewall to apply these changes
  1481.     firewall-cmd --reload
  1482.     return 0
  1483.   # Check for proper kernel modules to prevent failure
  1484.   elif modinfo ip_tables &> /dev/null && command -v iptables &> /dev/null; then
  1485.     # If chain Policy is not ACCEPT or last Rule is not ACCEPT
  1486.     # then check and insert our Rules above the DROP/REJECT Rule.
  1487.     if iptables -S INPUT | head -n1 | grep -qv '^-P.*ACCEPT$' || iptables -S INPUT | tail -n1 | grep -qv '^-\(A\|P\).*ACCEPT$'; then
  1488.       whiptail --title "Firewall in use" --yesno "We have detected a running firewall\\n\\nPi-hole currently requires HTTP and DNS port access.\\                                                                                                                                                                            n\\n\\n\\nInstall Pi-hole default firewall rules?" ${r} ${c} || \
  1489.       { echo -e "  ${INFO} Not installing firewall rulesets."; return 0; }
  1490.       echo -e "  ${TICK} Installing new IPTables firewall rulesets"
  1491.       # Check chain first, otherwise a new rule will duplicate old ones
  1492.       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
  1493.       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
  1494.       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
  1495.       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
  1496.       return 0
  1497.     fi
  1498.   # Othwerwise,
  1499.   else
  1500.     # no firewall is running
  1501.     echo -e "  ${INFO} No active firewall detected.. skipping firewall configuration"
  1502.     # so just exit
  1503.     return 0
  1504.   fi
  1505.   echo -e "  ${INFO} Skipping firewall configuration"
  1506. }
  1507.  
  1508. #
  1509. finalExports() {
  1510.   # If the Web interface is not set to be installed,
  1511.   if [[ "${INSTALL_WEB}" == false ]]; then
  1512.     # and if there is not an IPv4 address,
  1513.     if [[ "${IPV4_ADDRESS}" ]]; then
  1514.       # there is no block page, so set IPv4 to 0.0.0.0 (all IP addresses)
  1515.       IPV4_ADDRESS="0.0.0.0"
  1516.     fi
  1517.     if [[ "${IPV6_ADDRESS}" ]]; then
  1518.       # and IPv6 to ::/0
  1519.       IPV6_ADDRESS="::/0"
  1520.     fi
  1521.   fi
  1522.  
  1523.   # If the setup variable file exists,
  1524.   if [[ -e "${setupVars}" ]]; then
  1525.     # update the variables in the file
  1526.     sed -i.update.bak '/PIHOLE_INTERFACE/d;/IPV4_ADDRESS/d;/IPV6_ADDRESS/d;/PIHOLE_DNS_1/d;/PIHOLE_DNS_2/d;/QUERY_LOGGING/d;/INSTALL_WEB/d;/LIGHT                                                                                                                                                                            TPD_ENABLED/d;' "${setupVars}"
  1527.   fi
  1528.   # echo the information to the user
  1529.     {
  1530.   echo "PIHOLE_INTERFACE=${PIHOLE_INTERFACE}"
  1531.   echo "IPV4_ADDRESS=${IPV4_ADDRESS}"
  1532.   echo "IPV6_ADDRESS=${IPV6_ADDRESS}"
  1533.   echo "PIHOLE_DNS_1=${PIHOLE_DNS_1}"
  1534.   echo "PIHOLE_DNS_2=${PIHOLE_DNS_2}"
  1535.   echo "QUERY_LOGGING=${QUERY_LOGGING}"
  1536.   echo "INSTALL_WEB=${INSTALL_WEB}"
  1537.   echo "LIGHTTPD_ENABLED=${LIGHTTPD_ENABLED}"
  1538.     }>> "${setupVars}"
  1539.  
  1540.   # Bring in the current settings and the functions to manipulate them
  1541.   source "${setupVars}"
  1542.   source "${PI_HOLE_LOCAL_REPO}/advanced/Scripts/webpage.sh"
  1543.  
  1544.   # Look for DNS server settings which would have to be reapplied
  1545.   ProcessDNSSettings
  1546.  
  1547.   # Look for DHCP server settings which would have to be reapplied
  1548.   ProcessDHCPSettings
  1549. }
  1550.  
  1551. # Install the logrotate script
  1552. installLogrotate() {
  1553.  
  1554.   local str="Installing latest logrotate script"
  1555.   echo ""
  1556.   echo -ne "  ${INFO} ${str}..."
  1557.   # Copy the file over from the local repo
  1558.   cp ${PI_HOLE_LOCAL_REPO}/advanced/logrotate /etc/pihole/logrotate
  1559.   # Different operating systems have different user / group
  1560.   # settings for logrotate that makes it impossible to create
  1561.   # a static logrotate file that will work with e.g.
  1562.   # Rasbian and Ubuntu at the same time. Hence, we have to
  1563.   # customize the logrotate script here in order to reflect
  1564.   # the local properties of the /var/log directory
  1565.   logusergroup="$(stat -c '%U %G' /var/log)"
  1566.   # If the variable has a value,
  1567.   if [[ ! -z "${logusergroup}" ]]; then
  1568.     #
  1569.     sed -i "s/# su #/su ${logusergroup}/g;" /etc/pihole/logrotate
  1570.   fi
  1571.   echo -e "${OVER}  ${TICK} ${str}"
  1572. }
  1573.  
  1574. # Install base files and web interface
  1575. installPihole() {
  1576.   # Create the pihole user
  1577.   create_pihole_user
  1578.  
  1579.   # If the user wants to install the Web interface,
  1580.   if [[ "${INSTALL_WEB}" == true ]]; then
  1581.     if [[ ! -d "/var/www/html" ]]; then
  1582.       # make the Web directory if necessary
  1583.       mkdir -p /var/www/html
  1584.     fi
  1585.     # Set the owner and permissions
  1586.     chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/www/html
  1587.     chmod 775 /var/www/html
  1588.     # Give pihole access to the Web server group
  1589.     usermod -a -G ${LIGHTTPD_GROUP} pihole
  1590.     # If the lighttpd command is executable,
  1591.     if [[ -x "$(command -v lighty-enable-mod)" ]]; then
  1592.       # enable fastcgi and fastcgi-php
  1593.       lighty-enable-mod fastcgi fastcgi-php > /dev/null || true
  1594.     else
  1595.       # Othweise, show info about installing them
  1596.       echo -e  "  ${INFO} Warning: 'lighty-enable-mod' utility not found
  1597.       Please ensure fastcgi is enabled if you experience issues\\n"
  1598.     fi
  1599.   fi
  1600.   # Install scripts,
  1601.   installScripts
  1602.   # configs,
  1603.   installConfigs
  1604.   # and create the log file
  1605.   CreateLogFile
  1606.   # If the user wants to install the dashboard,
  1607.   if [[ "${INSTALL_WEB}" == true ]]; then
  1608.     # do so
  1609.     installPiholeWeb
  1610.   fi
  1611.   # Install the cron file
  1612.   installCron
  1613.   # Install the logrotate file
  1614.   installLogrotate
  1615.   # Check if FTL is installed
  1616.   FTLdetect || echo -e "  ${CROSS} FTL Engine not installed"
  1617.   # Configure the firewall
  1618.   configureFirewall
  1619.  
  1620.   #update setupvars.conf with any variables that may or may not have been changed during the install
  1621.   finalExports
  1622. }
  1623.  
  1624. # At some point in the future this list can be pruned, for now we'll need it to ensure updates don't break.
  1625. # Refactoring of install script has changed the name of a couple of variables. Sort them out here.
  1626. accountForRefactor() {
  1627.   sed -i 's/piholeInterface/PIHOLE_INTERFACE/g' ${setupVars}
  1628.   sed -i 's/IPv4_address/IPV4_ADDRESS/g' ${setupVars}
  1629.   sed -i 's/IPv4addr/IPV4_ADDRESS/g' ${setupVars}
  1630.   sed -i 's/IPv6_address/IPV6_ADDRESS/g' ${setupVars}
  1631.   sed -i 's/piholeIPv6/IPV6_ADDRESS/g' ${setupVars}
  1632.   sed -i 's/piholeDNS1/PIHOLE_DNS_1/g' ${setupVars}
  1633.   sed -i 's/piholeDNS2/PIHOLE_DNS_2/g' ${setupVars}
  1634. }
  1635.  
  1636. updatePihole() {
  1637.   accountForRefactor
  1638.   # Install base files and web interface
  1639.   installScripts
  1640.   # Install config files
  1641.   installConfigs
  1642.   # Create the log file
  1643.   CreateLogFile
  1644.   # If the user wants to install the dasboard,
  1645.   if [[ "${INSTALL_WEB}" == true ]]; then
  1646.     # do so
  1647.     installPiholeWeb
  1648.   fi
  1649.   # Install the cron file
  1650.   installCron
  1651.   # Install logrotate
  1652.   installLogrotate
  1653.   # Detect if FTL is installed
  1654.   FTLdetect || echo -e "  ${CROSS} FTL Engine not installed."
  1655.  
  1656.   #update setupvars.conf with any variables that may or may not have been changed during the install
  1657.   finalExports
  1658.  
  1659. }
  1660.  
  1661.  
  1662. # SELinux
  1663. checkSelinux() {
  1664.   # If the getenforce command exists,
  1665.   if command -v getenforce &> /dev/null; then
  1666.     # Store the current mode in a variable
  1667.     enforceMode=$(getenforce)
  1668.     echo -e "\\n  ${INFO} SELinux mode detected: ${enforceMode}"
  1669.  
  1670.     # If it's enforcing,
  1671.     if [[ "${enforceMode}" == "Enforcing" ]]; then
  1672.       # Explain Pi-hole does not support it yet
  1673.       whiptail --defaultno --title "SELinux Enforcing Detected" --yesno "SELinux is being ENFORCED on your system! \\n\\nPi-hole currently does n                                                                                                                                                                            ot support SELinux, but you may still continue with the installation.\\n\\nNote: Web Admin will not be fully functional unless you set your polic                                                                                                                                                                            ies correctly\\n\\nContinue installing Pi-hole?" ${r} ${c} || \
  1674.         { echo -e "\\n  ${COL_LIGHT_RED}SELinux Enforcing detected, exiting installer${COL_NC}"; exit 1; }
  1675.       echo -e "  ${INFO} Continuing installation with SELinux Enforcing
  1676.   ${INFO} Please refer to official SELinux documentation to create a custom policy"
  1677.     fi
  1678.   fi
  1679. }
  1680.  
  1681. # Installation complete message with instructions for the user
  1682. displayFinalMessage() {
  1683.   # If
  1684.   if [[ "${#1}" -gt 0 ]] ; then
  1685.     pwstring="$1"
  1686.   # else, if the dashboard password in the setup variables exists,
  1687.   elif [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) -gt 0 ]]; then
  1688.     # set a variable for evaluation later
  1689.     pwstring="unchanged"
  1690.   else
  1691.     # set a variable for evaluation later
  1692.     pwstring="NOT SET"
  1693.   fi
  1694.    # If the user wants to install the dashboard,
  1695.    if [[ "${INSTALL_WEB}" == true ]]; then
  1696.        # Store a message in a variable and display it
  1697.        additional="View the web interface at http://pi.hole/admin or http://${IPV4_ADDRESS%/*}/admin
  1698.  
  1699. Your Admin Webpage login password is ${pwstring}"
  1700.    fi
  1701.  
  1702.   # Final completion message to user
  1703.   whiptail --msgbox --backtitle "Make it so." --title "Installation Complete!" "Configure your devices to use the Pi-hole as their DNS server usi                                                                                                                                                                            ng:
  1704.  
  1705. IPv4:   ${IPV4_ADDRESS%/*}
  1706. IPv6:   ${IPV6_ADDRESS:-"Not Configured"}
  1707.  
  1708. If you set a new IP address, you should restart the Pi.
  1709.  
  1710. The install log is in /etc/pihole.
  1711.  
  1712. ${additional}" ${r} ${c}
  1713. }
  1714.  
  1715. update_dialogs() {
  1716.   # If pihole -r "reconfigure" option was selected,
  1717.   if [[ "${reconfigure}" = true ]]; then
  1718.     # set some variables that will be used
  1719.     opt1a="Repair"
  1720.     opt1b="This will retain existing settings"
  1721.     strAdd="You will remain on the same version"
  1722.   # Othweise,
  1723.   else
  1724.     # set some variables with different values
  1725.     opt1a="Update"
  1726.     opt1b="This will retain existing settings."
  1727.     strAdd="You will be updated to the latest version."
  1728.   fi
  1729.   opt2a="Reconfigure"
  1730.   opt2b="This will allow you to enter new settings"
  1731.  
  1732.   # Display the information to the user
  1733.   UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\\n\\nWe have detected an existing install.\\n\\nPlease choose from the follo                                                                                                                                                                            wing options: \\n($strAdd)" ${r} ${c} 2 \
  1734.   "${opt1a}"  "${opt1b}" \
  1735.   "${opt2a}"  "${opt2b}" 3>&2 2>&1 1>&3) || \
  1736.   { echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
  1737.  
  1738.   # Set the variable based on if the user chooses
  1739.   case ${UpdateCmd} in
  1740.     # repair, or
  1741.     ${opt1a})
  1742.       echo -e "  ${INFO} ${opt1a} option selected"
  1743.       useUpdateVars=true
  1744.       ;;
  1745.     # reconfigure,
  1746.     ${opt2a})
  1747.       echo -e "  ${INFO} ${opt2a} option selected"
  1748.       useUpdateVars=false
  1749.       ;;
  1750.     esac
  1751. }
  1752.  
  1753. clone_or_update_repos() {
  1754.   # If the user wants to reconfigure,
  1755.   if [[ "${reconfigure}" == true ]]; then
  1756.     echo "  ${INFO} Performing reconfiguration, skipping download of local repos"
  1757.     # Reset the Core repo
  1758.     resetRepo ${PI_HOLE_LOCAL_REPO} || \
  1759.       { echo -e "  ${COL_LIGHT_RED}Unable to reset ${PI_HOLE_LOCAL_REPO}, exiting installer${COL_NC}"; \
  1760.         exit 1; \
  1761.       }
  1762.     # If the Web interface was installed,
  1763.     if [[ "${INSTALL_WEB}" == true ]]; then
  1764.       # reset it's repo
  1765.       resetRepo ${webInterfaceDir} || \
  1766.         { echo -e "  ${COL_LIGHT_RED}Unable to reset ${webInterfaceDir}, exiting installer${COL_NC}"; \
  1767.           exit 1; \
  1768.         }
  1769.     fi
  1770.   # Otherwise, a repair is happening
  1771.   else
  1772.     # so get git files for Core
  1773.     getGitFiles ${PI_HOLE_LOCAL_REPO} ${piholeGitUrl} || \
  1774.       { echo -e "  ${COL_LIGHT_RED}Unable to clone ${piholeGitUrl} into ${PI_HOLE_LOCAL_REPO}, unable to continue${COL_NC}"; \
  1775.         exit 1; \
  1776.       }
  1777.       # If the Web interface was installed,
  1778.       if [[ "${INSTALL_WEB}" == true ]]; then
  1779.         # get the Web git files
  1780.         getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl} || \
  1781.         { echo -e "  ${COL_LIGHT_RED}Unable to clone ${webInterfaceGitUrl} into ${webInterfaceDir}, exiting installer${COL_NC}"; \
  1782.           exit 1; \
  1783.         }
  1784.       fi
  1785.   fi
  1786. }
  1787.  
  1788. # Download FTL binary to random temp directory and install FTL binary
  1789. FTLinstall() {
  1790.   # Local, named variables
  1791.   local binary="${1}"
  1792.   local latesttag
  1793.   local str="Downloading and Installing FTL"
  1794.   echo -ne "  ${INFO} ${str}..."
  1795.  
  1796.   # Find the latest version tag for FTL
  1797.   latesttag=$(curl -sI https://github.com/pi-hole/FTL/releases/latest | grep "Location" | awk -F '/' '{print $NF}')
  1798.   # Tags should always start with v, check for that.
  1799.   if [[ ! "${latesttag}" == v* ]]; then
  1800.     echo -e "${OVER}  ${CROSS} ${str}"
  1801.     echo -e "  ${COL_LIGHT_RED}Error: Unable to get latest release location from GitHub${COL_NC}"
  1802.     return 1
  1803.   fi
  1804.  
  1805.   # Move into the temp ftl directory
  1806.   pushd "$(mktemp -d)" || { echo "Unable to make temporary directory for FTL binary download"; return 1; }
  1807.  
  1808.   # Always replace pihole-FTL.service
  1809.   install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/pihole-FTL.service" "/etc/init.d/pihole-FTL"
  1810.  
  1811.   # If the download worked,
  1812.   if curl -sSL --fail "https://github.com/pi-hole/FTL/releases/download/${latesttag%$'\r'}/${binary}" -o "${binary}"; then
  1813.     # get sha1 of the binary we just downloaded for verification.
  1814.     curl -sSL --fail "https://github.com/pi-hole/FTL/releases/download/${latesttag%$'\r'}/${binary}.sha1" -o "${binary}.sha1"
  1815.  
  1816.     # If we downloaded binary file (as opposed to text),
  1817.     if sha1sum --status --quiet -c "${binary}".sha1; then
  1818.       echo -n "transferred... "
  1819.       # Stop FTL
  1820.       stop_service pihole-FTL &> /dev/null
  1821.       # Install the new version with the correct permissions
  1822.       install -T -m 0755 "${binary}" /usr/bin/pihole-FTL
  1823.       # Move back into the original directory the user was in
  1824.       popd || { echo "Unable to return to original directory after FTL binary download."; return 1; }
  1825.       # Install the FTL service
  1826.       echo -e "${OVER}  ${TICK} ${str}"
  1827.       return 0
  1828.     # Otherise,
  1829.     else
  1830.       # the download failed, so just go back to the original directory
  1831.       popd || { echo "Unable to return to original directory after FTL binary download."; return 1; }
  1832.       echo -e "${OVER}  ${CROSS} ${str}"
  1833.       echo -e "  ${COL_LIGHT_RED}Error: Download of binary from Github failed${COL_NC}"
  1834.       return 1
  1835.     fi
  1836.   # Otherwise,
  1837.   else
  1838.     popd || { echo "Unable to return to original directory after FTL binary download."; return 1; }
  1839.     echo -e "${OVER}  ${CROSS} ${str}"
  1840.     # The URL could not be found
  1841.     echo -e "  ${COL_LIGHT_RED}Error: URL not found${COL_NC}"
  1842.     return 1
  1843.   fi
  1844. }
  1845.  
  1846. # Detect suitable FTL binary platform
  1847. FTLdetect() {
  1848.   echo ""
  1849.   echo -e "  ${INFO} FTL Checks..."
  1850.  
  1851.   # Local, named variables
  1852.   local machine
  1853.   local binary
  1854.  
  1855.   # Store architecture in a variable
  1856.   machine=$(uname -m)
  1857.  
  1858.   local str="Detecting architecture"
  1859.   echo -ne "  ${INFO} ${str}..."
  1860.   # If the machine is arm or aarch
  1861.   if [[ "${machine}" == "arm"* || "${machine}" == *"aarch"* ]]; then
  1862.     # ARM
  1863.     #
  1864.     local rev
  1865.     rev=$(uname -m | sed "s/[^0-9]//g;")
  1866.     #
  1867.     local lib
  1868.     lib=$(ldd /bin/ls | grep -E '^\s*/lib' | awk '{ print $1 }')
  1869.     #
  1870.     if [[ "${lib}" == "/lib/ld-linux-aarch64.so.1" ]]; then
  1871.       echo -e "${OVER}  ${TICK} Detected ARM-aarch64 architecture"
  1872.       # set the binary to be used
  1873.       binary="pihole-FTL-aarch64-linux-gnu"
  1874.     #
  1875.     elif [[ "${lib}" == "/lib/ld-linux-armhf.so.3" ]]; then
  1876.       #
  1877.       if [[ "${rev}" -gt 6 ]]; then
  1878.         echo -e "${OVER}  ${TICK} Detected ARM-hf architecture (armv7+)"
  1879.         # set the binary to be used
  1880.         binary="pihole-FTL-arm-linux-gnueabihf"
  1881.       # Otherwise,
  1882.       else
  1883.         echo -e "${OVER}  ${TICK} Detected ARM-hf architecture (armv6 or lower) Using ARM binary"
  1884.         # set the binary to be used
  1885.         binary="pihole-FTL-arm-linux-gnueabi"
  1886.       fi
  1887.     else
  1888.       echo -e "${OVER}  ${TICK} Detected ARM architecture"
  1889.       # set the binary to be used
  1890.       binary="pihole-FTL-arm-linux-gnueabi"
  1891.     fi
  1892.   elif [[ "${machine}" == "ppc" ]]; then
  1893.     # PowerPC
  1894.     echo -e "${OVER}  ${TICK} Detected PowerPC architecture"
  1895.     # set the binary to be used
  1896.     binary="pihole-FTL-powerpc-linux-gnu"
  1897.   elif [[ "${machine}" == "x86_64" ]]; then
  1898.     # 64bit
  1899.     echo -e "${OVER}  ${TICK} Detected x86_64 architecture"
  1900.     # set the binary to be used
  1901.     binary="pihole-FTL-linux-x86_64"
  1902.   else
  1903.     # Something else - we try to use 32bit executable and warn the user
  1904.     if [[ ! "${machine}" == "i686" ]]; then
  1905.       echo -e "${OVER}  ${CROSS} ${str}...
  1906.       ${COL_LIGHT_RED}Not able to detect architecture (unknown: ${machine}), trying 32bit executable${COL_NC}
  1907.       Contact Pi-hole Support if you experience issues (e.g: FTL not running)"
  1908.     else
  1909.       echo -e "${OVER}  ${TICK} Detected 32bit (i686) architecture"
  1910.     fi
  1911.     binary="pihole-FTL-linux-x86_32"
  1912.   fi
  1913.  
  1914.   #In the next section we check to see if FTL is already installed (in case of pihole -r).
  1915.   #If the installed version matches the latest version, then check the installed sha1sum of the binary vs the remote sha1sum. If they do not matc                                                                                                                                                                            h, then download
  1916.   echo -e "  ${INFO} Checking for existing FTL binary..."
  1917.  
  1918.   local ftlLoc=$(which pihole-FTL 2>/dev/null)
  1919.  
  1920.   if [[ ${ftlLoc} ]]; then
  1921.     local FTLversion=$(/usr/bin/pihole-FTL tag)
  1922.           local FTLlatesttag=$(curl -sI https://github.com/pi-hole/FTL/releases/latest | grep 'Location' | awk -F '/' '{print $NF}' | tr -d '\r\n                                                                                                                                                                            ')
  1923.  
  1924.           if [[ "${FTLversion}" != "${FTLlatesttag}" ]]; then
  1925.                   # Install FTL
  1926.       FTLinstall "${binary}" || return 1
  1927.           else
  1928.             echo -e "  ${INFO} Latest FTL Binary already installed (${FTLlatesttag}). Confirming Checksum..."
  1929.  
  1930.             local remoteSha1=$(curl -sSL --fail "https://github.com/pi-hole/FTL/releases/download/${FTLversion%$'\r'}/${binary}.sha1" | cut -d '                                                                                                                                                                             ' -f 1)
  1931.             local localSha1=$(sha1sum "$(which pihole-FTL)" | cut -d ' ' -f 1)
  1932.  
  1933.             if [[ "${remoteSha1}" != "${localSha1}" ]]; then
  1934.               echo -e "  ${INFO} Corruption detected..."
  1935.               FTLinstall "${binary}" || return 1
  1936.             else
  1937.               echo -e "  ${INFO} Checksum correct. No need to download!"
  1938.             fi
  1939.           fi
  1940.         else
  1941.           # Install FTL
  1942.     FTLinstall "${binary}" || return 1
  1943.   fi
  1944. }
  1945.  
  1946. make_temporary_log() {
  1947.   # Create a random temporary file for the log
  1948.   TEMPLOG=$(mktemp /tmp/pihole_temp.XXXXXX)
  1949.   # Open handle 3 for templog
  1950.   # https://stackoverflow.com/questions/18460186/writing-outputs-to-log-file-and-console
  1951.   exec 3>"$TEMPLOG"
  1952.   # Delete templog, but allow for addressing via file handle
  1953.   # This lets us write to the log without having a temporary file on the drive, which
  1954.   # is meant to be a security measure so there is not a lingering file on the drive during the install process
  1955.   rm "$TEMPLOG"
  1956. }
  1957.  
  1958. copy_to_install_log() {
  1959.   # Copy the contents of file descriptor 3 into the install log
  1960.   # Since we use color codes such as '\e[1;33m', they should be removed
  1961.   sed 's/[[0-9;]\{1,5\}m//g' < /proc/$$/fd/3 > "${installLogLoc}"
  1962. }
  1963.  
  1964. main() {
  1965.   ######## FIRST CHECK ########
  1966.   # Must be root to install
  1967.   local str="Root user check"
  1968.   echo ""
  1969.  
  1970.   # If the user's id is zero,
  1971.   if [[ "${EUID}" -eq 0 ]]; then
  1972.     # they are root and all is good
  1973.     echo -e "  ${TICK} ${str}"
  1974.     # Show the Pi-hole logo so people know it's genuine since the logo and name are trademarked
  1975.     show_ascii_berry
  1976.     make_temporary_log
  1977.   # Otherwise,
  1978.   else
  1979.     # They do not have enough privileges, so let the user know
  1980.     echo -e "  ${CROSS} ${str}
  1981.       ${COL_LIGHT_RED}Script called with non-root privileges${COL_NC}
  1982.       The Pi-hole requires elevated privileges to install and run
  1983.       Please check the installer for any concerns regarding this requirement
  1984.       Make sure to download this script from a trusted source\\n"
  1985.     echo -ne "  ${INFO} Sudo utility check"
  1986.  
  1987.     # If the sudo command exists,
  1988.     if command -v sudo &> /dev/null; then
  1989.       echo -e "${OVER}  ${TICK} Sudo utility check"
  1990.       # Download the install script and run it with admin rights
  1991.       exec curl -sSL https://raw.githubusercontent.com/pi-hole/pi-hole/master/automated%20install/basic-install.sh | sudo bash "$@"
  1992.       exit $?
  1993.     # Otherwise,
  1994.     else
  1995.       # Let them know they need to run it as root
  1996.       echo -e "${OVER}  ${CROSS} Sudo utility check
  1997.       Sudo is needed for the Web Interface to run pihole commands\\n
  1998.   ${COL_LIGHT_RED}Please re-run this installer as root${COL_NC}"
  1999.       exit 1
  2000.     fi
  2001.   fi
  2002.  
  2003.   # Check for supported distribution
  2004.   distro_check
  2005.  
  2006.   # Check arguments for the undocumented flags
  2007.   for var in "$@"; do
  2008.     case "$var" in
  2009.       "--reconfigure" ) reconfigure=true;;
  2010.       "--i_do_not_follow_recommendations" ) skipSpaceCheck=true;;
  2011.       "--unattended" ) runUnattended=true;;
  2012.     esac
  2013.   done
  2014.  
  2015.   # If the setup variable file exists,
  2016.   if [[ -f "${setupVars}" ]]; then
  2017.     # if it's running unattended,
  2018.     if [[ "${runUnattended}" == true ]]; then
  2019.       echo -e "  ${INFO} Performing unattended setup, no whiptail dialogs will be displayed"
  2020.       # Use the setup variables
  2021.       useUpdateVars=true
  2022.     # Otherwise,
  2023.     else
  2024.       # show the available options (repair/reconfigure)
  2025.       update_dialogs
  2026.     fi
  2027.   fi
  2028.  
  2029.   # Start the installer
  2030.   # Verify there is enough disk space for the install
  2031.   if [[ "${skipSpaceCheck}" == true ]]; then
  2032.     echo -e "  ${INFO} Skipping free disk space verification"
  2033.   else
  2034.     verifyFreeDiskSpace
  2035.   fi
  2036.  
  2037.   # Update package cache
  2038.   update_package_cache || exit 1
  2039.  
  2040.   # Notify user of package availability
  2041.   notify_package_updates_available
  2042.  
  2043.   # Install packages used by this installation script
  2044.   install_dependent_packages INSTALLER_DEPS[@]
  2045.  
  2046.    # Check if SELinux is Enforcing
  2047.   checkSelinux
  2048.  
  2049.   if [[ "${useUpdateVars}" == false ]]; then
  2050.     # Display welcome dialogs
  2051.     welcomeDialogs
  2052.     # Create directory for Pi-hole storage
  2053.     mkdir -p /etc/pihole/
  2054.  
  2055.     stop_service dnsmasq
  2056.     if [[ "${INSTALL_WEB}" == true ]]; then
  2057.       stop_service lighttpd
  2058.     fi
  2059.     # Determine available interfaces
  2060.     get_available_interfaces
  2061.     # Find interfaces and let the user choose one
  2062.     chooseInterface
  2063.     # Decide what upstream DNS Servers to use
  2064.     setDNS
  2065.     # Let the user decide if they want to block ads over IPv4 and/or IPv6
  2066.     use4andor6
  2067.     # Let the user decide if they want the web interface to be installed automatically
  2068.     setAdminFlag
  2069.     # Let the user decide if they want query logging enabled...
  2070.     setLogging
  2071.     # Clone/Update the repos
  2072.     clone_or_update_repos
  2073.  
  2074.     # Install packages used by the Pi-hole
  2075.     if [[ "${INSTALL_WEB}" == true ]]; then
  2076.       # Install the Web dependencies
  2077.       DEPS=("${PIHOLE_DEPS[@]}" "${PIHOLE_WEB_DEPS[@]}")
  2078.     # Otherwise,
  2079.     else
  2080.       # just install the Core dependencies
  2081.       DEPS=("${PIHOLE_DEPS[@]}")
  2082.     fi
  2083.  
  2084.     install_dependent_packages DEPS[@]
  2085.  
  2086.     # On some systems, lighttpd is not enabled on first install. We need to enable it here if the user
  2087.     # has chosen to install the web interface, else the `LIGHTTPD_ENABLED` check will fail
  2088.     if [[ "${INSTALL_WEB}" == true ]]; then
  2089.       enable_service lighttpd
  2090.     fi
  2091.  
  2092.     if [[ -x "$(command -v systemctl)" ]]; then
  2093.       # Value will either be 1, if true, or 0
  2094.       LIGHTTPD_ENABLED=$(systemctl is-enabled lighttpd | grep -c 'enabled' || true)
  2095.     else
  2096.       # Value will either be 1, if true, or 0
  2097.       LIGHTTPD_ENABLED=$(service lighttpd status | awk '/Loaded:/ {print $0}' | grep -c 'enabled' || true)
  2098.     fi
  2099.  
  2100.     # Install and log everything to a file
  2101.     installPihole | tee -a /proc/$$/fd/3
  2102.   else
  2103.     # Source ${setupVars} to use predefined user variables in the functions
  2104.     source ${setupVars}
  2105.  
  2106.     # Clone/Update the repos
  2107.     clone_or_update_repos
  2108.  
  2109.     # Install packages used by the Pi-hole
  2110.     if [[ "${INSTALL_WEB}" == true ]]; then
  2111.       # Install the Web dependencies
  2112.       DEPS=("${PIHOLE_DEPS[@]}" "${PIHOLE_WEB_DEPS[@]}")
  2113.     # Otherwise,
  2114.     else
  2115.       # just install the Core dependencies
  2116.       DEPS=("${PIHOLE_DEPS[@]}")
  2117.     fi
  2118.     install_dependent_packages DEPS[@]
  2119.  
  2120.     if [[ -x "$(command -v systemctl)" ]]; then
  2121.       # Value will either be 1, if true, or 0
  2122.       LIGHTTPD_ENABLED=$(systemctl is-enabled lighttpd | grep -c 'enabled' || true)
  2123.     else
  2124.       # Value will either be 1, if true, or 0
  2125.       LIGHTTPD_ENABLED=$(service lighttpd status | awk '/Loaded:/ {print $0}' | grep -c 'enabled' || true)
  2126.     fi
  2127.     updatePihole | tee -a /proc/$$/fd/3
  2128.   fi
  2129.  
  2130.   # Copy the temp log file into final log location for storage
  2131.   copy_to_install_log
  2132.  
  2133.   if [[ "${INSTALL_WEB}" == true ]]; then
  2134.     # Add password to web UI if there is none
  2135.     pw=""
  2136.     # If no password is set,
  2137.     if [[ $(grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) == 0 ]] ; then
  2138.         # generate a random password
  2139.         pw=$(tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 8)
  2140.         # shellcheck disable=SC1091
  2141.         . /opt/pihole/webpage.sh
  2142.         echo "WEBPASSWORD=$(HashPassword ${pw})" >> ${setupVars}
  2143.     fi
  2144.   fi
  2145.  
  2146.   echo -e "  ${INFO} Restarting services..."
  2147.   # Start services
  2148.   start_service dnsmasq
  2149.   enable_service dnsmasq
  2150.  
  2151.   # If the Web server was installed,
  2152.   if [[ "${INSTALL_WEB}" == true ]]; then
  2153.  
  2154.     if [[ "${LIGHTTPD_ENABLED}" == "1" ]]; then
  2155.       start_service lighttpd
  2156.       enable_service lighttpd
  2157.     else
  2158.       echo -e "  ${INFO} Lighttpd is disabled, skipping service restart"
  2159.     fi
  2160.   fi
  2161.  
  2162.   # Enable FTL
  2163.   start_service pihole-FTL
  2164.   enable_service pihole-FTL
  2165.  
  2166.   # Download and compile the aggregated block list
  2167.   runGravity
  2168.  
  2169.   # Force an update of the updatechecker
  2170.   . /opt/pihole/updatecheck.sh
  2171.   . /opt/pihole/updatecheck.sh x remote
  2172.  
  2173.   #
  2174.   if [[ "${useUpdateVars}" == false ]]; then
  2175.       displayFinalMessage "${pw}"
  2176.   fi
  2177.  
  2178.   # If the Web interface was installed,
  2179.   if [[ "${INSTALL_WEB}" == true ]]; then
  2180.     # If there is a password,
  2181.     if (( ${#pw} > 0 )) ; then
  2182.       # display the password
  2183.       echo -e "  ${INFO} Web Interface password: ${COL_LIGHT_GREEN}${pw}${COL_NC}
  2184.       This can be changed using 'pihole -a -p'\\n"
  2185.     fi
  2186.   fi
  2187.  
  2188.   #
  2189.   if [[ "${useUpdateVars}" == false ]]; then
  2190.     # If the Web interface was installed,
  2191.     if [[ "${INSTALL_WEB}" == true ]]; then
  2192.       echo -e "  View the web interface at http://pi.hole/admin or http://${IPV4_ADDRESS%/*}/admin"
  2193.       echo ""
  2194.     fi
  2195.     # Explain to the user how to use Pi-hole as their DNS server
  2196.     echo "  You may now configure your devices to use the Pi-hole as their DNS server"
  2197.     [[ -n "${IPV4_ADDRESS%/*}" ]] && echo -e "  ${INFO} Pi-hole DNS (IPv4): ${IPV4_ADDRESS%/*}"
  2198.     [[ -n "${IPV6_ADDRESS}" ]] && echo -e "  ${INFO} Pi-hole DNS (IPv6): ${IPV6_ADDRESS}"
  2199.     echo -e "  If you set a new IP address, please restart the server running the Pi-hole"
  2200.     #
  2201.     INSTALL_TYPE="Installation"
  2202.   else
  2203.     #
  2204.     INSTALL_TYPE="Update"
  2205.   fi
  2206.  
  2207.   # Display where the log file is
  2208.   echo -e "\\n  ${INFO} The install log is located at: ${installLogLoc}
  2209.   ${COL_LIGHT_GREEN}${INSTALL_TYPE} Complete! ${COL_NC}"
  2210.  
  2211. }
  2212.  
  2213. #
  2214. if [[ "${PH_TEST}" != true ]] ; then
  2215.   main "$@"
  2216. fi
  2217. + [[ '' != true ]]
  2218. + main
  2219. + local 'str=Root user check'
  2220. + echo ''
  2221.  
  2222. + [[ 0 -eq 0 ]]
  2223. + echo -e '  [\e[1;32m✓\e[0m] Root user check'
  2224.   [✓] Root user check
  2225. + show_ascii_berry
  2226. + echo -e '
  2227.         \e[1;32m.;;,.
  2228.         .ccccc:,.
  2229.          :cccclll:.      ..,,
  2230.           :ccccclll.   ;ooodc
  2231.            '\''ccll:;ll .oooodc
  2232.              .;cll.;;looo:.
  2233.                  \e[1;31m.. '\'','\''.
  2234.                 .'\'',,,,,,'\''.
  2235.               .'\'',,,,,,,,,,.
  2236.             .'\'',,,,,,,,,,,,....
  2237.           ....'\'''\'''\'',,,,,,,'\''.......
  2238.         .........  ....  .........
  2239.         ..........      ..........
  2240.         ..........      ..........
  2241.         .........  ....  .........
  2242.           ........,,,,,,,'\''......
  2243.             ....'\'',,,,,,,,,,,,.
  2244.                .'\'',,,,,,,,,'\''.
  2245.                 .'\'',,,,,,'\''.
  2246.                   ..'\'''\'''\''.\e[0m
  2247. '
  2248.  
  2249.         .;;,.
  2250.         .ccccc:,.
  2251.          :cccclll:.      ..,,
  2252.           :ccccclll.   ;ooodc
  2253.            'ccll:;ll .oooodc
  2254.              .;cll.;;looo:.
  2255.                  .. ','.
  2256.                 .',,,,,,'.
  2257.               .',,,,,,,,,,.
  2258.             .',,,,,,,,,,,,....
  2259.           ....''',,,,,,,'.......
  2260.         .........  ....  .........
  2261.         ..........      ..........
  2262.         ..........      ..........
  2263.         .........  ....  .........
  2264.           ........,,,,,,,'......
  2265.             ....',,,,,,,,,,,,.
  2266.                .',,,,,,,,,'.
  2267.                 .',,,,,,'.
  2268.                   ..'''.
  2269.  
  2270. + make_temporary_log
  2271. mktemp /tmp/pihole_temp.XXXXXX
  2272. ++ mktemp /tmp/pihole_temp.XXXXXX
  2273. + TEMPLOG=/tmp/pihole_temp.FRKjsm
  2274. + exec
  2275. + rm /tmp/pihole_temp.FRKjsm
  2276. + distro_check
  2277. + command -v apt-get
  2278. + PKG_MANAGER=apt-get
  2279. + UPDATE_PKG_CACHE='apt-get update'
  2280. + PKG_INSTALL=(${PKG_MANAGER} --yes --no-install-recommends install)
  2281. + PKG_COUNT='apt-get -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true'
  2282. + apt-get install --dry-run iproute2
  2283. + iproute_pkg=iproute2
  2284. + apt-get install --dry-run php
  2285. + phpVer=php
  2286. + apt-get install --dry-run php-sqlite3
  2287. + phpSqlite=sqlite3
  2288. + INSTALLER_DEPS=(apt-utils dialog debconf dhcpcd5 git ${iproute_pkg} whiptail)
  2289. + PIHOLE_DEPS=(bc cron curl dnsmasq dnsutils iputils-ping lsof netcat sudo unzip wget idn2 sqlite3)
  2290. + PIHOLE_WEB_DEPS=(lighttpd ${phpVer}-common ${phpVer}-cgi ${phpVer}-${phpSqlite})
  2291. + LIGHTTPD_USER=www-data
  2292. + LIGHTTPD_GROUP=www-data
  2293. + LIGHTTPD_CFG=lighttpd.conf.debian
  2294. + DNSMASQ_USER=dnsmasq
  2295. + [[ -f /etc/pihole/setupVars.conf ]]
  2296. + [[ false == true ]]
  2297. + verifyFreeDiskSpace
  2298. + local 'str=Disk space check'
  2299. + local required_free_kilobytes=51200
  2300. + local existing_free_kilobytes
  2301. df -Pk | grep -m1 '\/$' | awk '{print $4}'
  2302. ++ df -Pk
  2303. ++ grep -m1 '\/$'
  2304. ++ awk '{print $4}'
  2305. + existing_free_kilobytes=904489940
  2306. + [[ 904489940 =~ ^([0-9])+$ ]]
  2307. + [[ 904489940 -lt 51200 ]]
  2308. + echo -e '  [\e[1;32m✓\e[0m] Disk space check'
  2309.   [✓] Disk space check
  2310. + update_package_cache
  2311. + local 'str=Update local cache of available packages'
  2312. + echo ''
  2313.  
  2314. + echo -ne '  [i] Update local cache of available packages...'
  2315.   [i] Update local cache of available packages...+ eval 'apt-get update'
  2316. + echo -e '\r\033[K  [\e[1;32m✓\e[0m] Update local cache of available packages'
  2317.   [✓] Update local cache of available packages
  2318. + notify_package_updates_available
  2319. + local 'str=Checking apt-get for upgraded packages'
  2320. + echo -ne '\n  [i] Checking apt-get for upgraded packages...'
  2321.  
  2322.   [i] Checking apt-get for upgraded packages...eval "${PKG_COUNT}"
  2323. ++ eval 'apt-get -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true'
  2324. apt-get -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true
  2325. +++ apt-get -s -o Debug::NoLocking=true upgrade
  2326. +++ grep -c '^Inst'
  2327. +++ true
  2328. + updatesToInstall=0
  2329. uname -r
  2330. ++ uname -r
  2331. + [[ -d /lib/modules/4.4.0-119-generic ]]
  2332. + [[ 0 -eq 0 ]]
  2333. + echo -e '\r\033[K  [\e[1;32m✓\e[0m] Checking apt-get for upgraded packages... up to date!'
  2334.   [✓] Checking apt-get for upgraded packages... up to date!
  2335. + echo ''
  2336.  
  2337. + install_dependent_packages 'INSTALLER_DEPS[@]'
  2338. + counter=1
  2339. + [[ 1 == 1 ]]
  2340. + echo -e '  [i] Installer Dependency checks...'
  2341.   [i] Installer Dependency checks...
  2342. + argArray1=("${!1}")
  2343. + declare -a argArray1
  2344. + declare -a installArray
  2345. + command -v debconf-apt-progress
  2346. + for i in '"${argArray1[@]}"'
  2347. + echo -ne '  [i] Checking for apt-utils...'
  2348.   [i] Checking for apt-utils...+ grep 'ok installed'
  2349. + dpkg-query -W '-f=${Status}' apt-utils
  2350. + echo -e '\r\033[K  [\e[1;32m✓\e[0m] Checking for apt-utils'
  2351.   [✓] Checking for apt-utils
  2352. + for i in '"${argArray1[@]}"'
  2353. + echo -ne '  [i] Checking for dialog...'
  2354.   [i] Checking for dialog...+ dpkg-query -W '-f=${Status}' dialog
  2355. + grep 'ok installed'
  2356. + echo -e '\r\033[K  [\e[1;32m✓\e[0m] Checking for dialog'
  2357.   [✓] Checking for dialog
  2358. + for i in '"${argArray1[@]}"'
  2359. + echo -ne '  [i] Checking for debconf...'
  2360.   [i] Checking for debconf...+ dpkg-query -W '-f=${Status}' debconf
  2361. + grep 'ok installed'
  2362. + echo -e '\r\033[K  [\e[1;32m✓\e[0m] Checking for debconf'
  2363.   [✓] Checking for debconf
  2364. + for i in '"${argArray1[@]}"'
  2365. + echo -ne '  [i] Checking for dhcpcd5...'
  2366.   [i] Checking for dhcpcd5...+ dpkg-query -W '-f=${Status}' dhcpcd5
  2367. + grep 'ok installed'
  2368. + echo -e '\r\033[K  [\e[1;32m✓\e[0m] Checking for dhcpcd5'
  2369.   [✓] Checking for dhcpcd5
  2370. + for i in '"${argArray1[@]}"'
  2371. + echo -ne '  [i] Checking for git...'
  2372.   [i] Checking for git...+ dpkg-query -W '-f=${Status}' git
  2373. + grep 'ok installed'
  2374. + echo -e '\r\033[K  [\e[1;32m✓\e[0m] Checking for git'
  2375.   [✓] Checking for git
  2376. + for i in '"${argArray1[@]}"'
  2377. + echo -ne '  [i] Checking for iproute2...'
  2378.   [i] Checking for iproute2...+ dpkg-query -W '-f=${Status}' iproute2
  2379. + grep 'ok installed'
  2380. + echo -e '\r\033[K  [\e[1;32m✓\e[0m] Checking for iproute2'
  2381.   [✓] Checking for iproute2
  2382. + for i in '"${argArray1[@]}"'
  2383. + echo -ne '  [i] Checking for whiptail...'
  2384.   [i] Checking for whiptail...+ dpkg-query -W '-f=${Status}' whiptail
  2385. + grep 'ok installed'
  2386. + echo -e '\r\033[K  [\e[1;32m✓\e[0m] Checking for whiptail'
  2387.   [✓] Checking for whiptail
  2388. + [[ 0 -gt 0 ]]
  2389. + echo ''
  2390.  
  2391. + return 0
  2392. + checkSelinux
  2393. + command -v getenforce
  2394. + [[ false == false ]]
  2395. + welcomeDialogs
  2396. + whiptail --msgbox --backtitle Welcome --title 'Pi-hole automated installer' '\n\nThis installer will transform your device into a network-wide                                                                                                                                                                             ad blocker!' 20 70
  2397. + 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' 20 70
  2398. + whiptail --msgbox --backtitle 'Initiating network interface' --title 'Static IP Needed' '\n\nThe Pi-hole is a SERVER so it needs a STATIC IP AD                                                                                                                                                                            DRESS to function properly.
  2399.  
  2400. In the next section, you can choose to use your current network settings (DHCP) or to manually edit them.' 20 70
  2401. + mkdir -p /etc/pihole/
  2402. + stop_service dnsmasq
  2403. + local 'str=Stopping dnsmasq service'
  2404. + echo ''
  2405.  
  2406. + echo -ne '  [i] Stopping dnsmasq service...'
  2407.   [i] Stopping dnsmasq service...+ command -v systemctl
  2408. + systemctl stop dnsmasq
  2409. + echo -e '\r\033[K  [\e[1;32m✓\e[0m] Stopping dnsmasq service...'
  2410.   [✓] Stopping dnsmasq service...
  2411. + [[ true == true ]]
  2412. + stop_service lighttpd
  2413. + local 'str=Stopping lighttpd service'
  2414. + echo ''
  2415.  
  2416. + echo -ne '  [i] Stopping lighttpd service...'
  2417.   [i] Stopping lighttpd service...+ command -v systemctl
  2418. + systemctl stop lighttpd
  2419. + echo -e '\r\033[K  [\e[1;32m✓\e[0m] Stopping lighttpd service...'
  2420.   [✓] Stopping lighttpd service...
  2421. + get_available_interfaces
  2422. ip --oneline link show up | grep -v "lo" | awk '{print $2}' | cut -d':' -f1 | cut -d'@' -f1
  2423. ++ ip --oneline link show up
  2424. ++ grep -v lo
  2425. ++ awk '{print $2}'
  2426. ++ cut -d@ -f1
  2427. ++ cut -d: -f1
  2428. + availableInterfaces='eno1
  2429. enp2s0
  2430. docker0
  2431. veth05f4131
  2432. veth0aab363
  2433. veth4ded25e
  2434. veth82f8812
  2435. vetha0d3c5c
  2436. veth0d465d5
  2437. vethac19731'
  2438. + chooseInterface
  2439. + interfacesArray=()
  2440. + local interfacesArray
  2441. + local interfaceCount
  2442. + local chooseInterfaceCmd
  2443. + local chooseInterfaceOptions
  2444. + local firstLoop=1
  2445. echo "${availableInterfaces}" | wc -l
  2446. ++ echo 'eno1
  2447. enp2s0
  2448. docker0
  2449. veth05f4131
  2450. veth0aab363
  2451. veth4ded25e
  2452. veth82f8812
  2453. vetha0d3c5c
  2454. veth0d465d5
  2455. vethac19731'
  2456. ++ wc -l
  2457. + interfaceCount=10
  2458. + [[ 10 -eq 1 ]]
  2459. + read -r line
  2460. + mode=OFF
  2461. + [[ 1 -eq 1 ]]
  2462. + firstLoop=0
  2463. + mode=ON
  2464. + interfacesArray+=("${line}" "available" "${mode}")
  2465. + read -r line
  2466. + mode=OFF
  2467. + [[ 0 -eq 1 ]]
  2468. + interfacesArray+=("${line}" "available" "${mode}")
  2469. + read -r line
  2470. + mode=OFF
  2471. + [[ 0 -eq 1 ]]
  2472. + interfacesArray+=("${line}" "available" "${mode}")
  2473. + read -r line
  2474. + mode=OFF
  2475. + [[ 0 -eq 1 ]]
  2476. + interfacesArray+=("${line}" "available" "${mode}")
  2477. + read -r line
  2478. + mode=OFF
  2479. + [[ 0 -eq 1 ]]
  2480. + interfacesArray+=("${line}" "available" "${mode}")
  2481. + read -r line
  2482. + mode=OFF
  2483. + [[ 0 -eq 1 ]]
  2484. + interfacesArray+=("${line}" "available" "${mode}")
  2485. + read -r line
  2486. + mode=OFF
  2487. + [[ 0 -eq 1 ]]
  2488. + interfacesArray+=("${line}" "available" "${mode}")
  2489. + read -r line
  2490. + mode=OFF
  2491. + [[ 0 -eq 1 ]]
  2492. + interfacesArray+=("${line}" "available" "${mode}")
  2493. + read -r line
  2494. + mode=OFF
  2495. + [[ 0 -eq 1 ]]
  2496. + interfacesArray+=("${line}" "available" "${mode}")
  2497. + read -r line
  2498. + mode=OFF
  2499. + [[ 0 -eq 1 ]]
  2500. + interfacesArray+=("${line}" "available" "${mode}")
  2501. + read -r line
  2502. + chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to select)" ${r} ${c} ${interfaceCount})
  2503. "${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty
  2504. ++ whiptail --separate-output --radiolist 'Choose An Interface (press space to select)' 20 70 10 eno1 available ON enp2s0 available OFF docker0 a                                                                                                                                                                            vailable OFF veth05f4131 available OFF veth0aab363 available OFF veth4ded25e available OFF veth82f8812 available OFF vetha0d3c5c available OFF ve                                                                                                                                                                            th0d465d5 available OFF vethac19731 available OFF
  2505. + chooseInterfaceOptions=enp2s0
  2506. + for desiredInterface in '${chooseInterfaceOptions}'
  2507. + PIHOLE_INTERFACE=enp2s0
  2508. + echo -e '  [i] Using interface: enp2s0'
  2509.   [i] Using interface: enp2s0
  2510. + setDNS
  2511. + local DNSSettingsCorrect
  2512. + DNSChooseOptions=(Google "" OpenDNS "" Level3 "" Norton "" Comodo "" DNSWatch "" Quad9 "" FamilyShield "" Custom "")
  2513. whiptail --separate-output --menu "Select Upstream DNS Provider. To use your own, select Custom." ${r} ${c} 7     "${DNSChooseOptions[@]}" 2>&1 >                                                                                                                                                                            /dev/tty
  2514. ++ whiptail --separate-output --menu 'Select Upstream DNS Provider. To use your own, select Custom.' 20 70 7 Google '' OpenDNS '' Level3 '' Norto                                                                                                                                                                            n '' Comodo '' DNSWatch '' Quad9 '' FamilyShield '' Custom ''
  2515. + DNSchoices=Google
  2516. + echo -ne '  [i] Using '
  2517.   [i] Using + case ${DNSchoices} in
  2518. + echo 'Google DNS servers'
  2519. Google DNS servers
  2520. + PIHOLE_DNS_1=8.8.8.8
  2521. + PIHOLE_DNS_2=8.8.4.4
  2522. + use4andor6
  2523. + local useIPv4
  2524. + local useIPv6
  2525. + cmd=(whiptail --separate-output --checklist "Select Protocols (press space to select)" ${r} ${c} 2)
  2526. + options=(IPv4 "Block ads over IPv4" on IPv6 "Block ads over IPv6" on)
  2527. "${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty
  2528. ++ whiptail --separate-output --checklist 'Select Protocols (press space to select)' 20 70 2 IPv4 'Block ads over IPv4' on IPv6 'Block ads over I                                                                                                                                                                            Pv6' on
  2529. + choices='IPv4
  2530. IPv6'
  2531. + for choice in '${choices}'
  2532. + case ${choice} in
  2533. + useIPv4=true
  2534. + for choice in '${choices}'
  2535. + case ${choice} in
  2536. + useIPv6=true
  2537. + [[ -n true ]]
  2538. + find_IPv4_information
  2539. + local route
  2540. ip route get 8.8.8.8
  2541. ++ ip route get 8.8.8.8
  2542. + route='8.8.8.8 via 192.168.0.1 dev enp2s0  src 192.168.0.3
  2543.     cache '
  2544. awk '{for (i=1; i<=NF; i++) if ($i~/dev/) print $(i+1)}' <<< "${route}"
  2545. ++ awk '{for (i=1; i<=NF; i++) if ($i~/dev/) print $(i+1)}'
  2546. + IPv4dev=enp2s0
  2547. awk '{print $7}' <<< "${route}"
  2548. ++ awk '{print $7}'
  2549. + IPv4bare=192.168.0.3
  2550. ip -o -f inet addr show | grep "${IPv4bare}" |  awk '{print $4}' | awk 'END {print}'
  2551. ++ ip -o -f inet addr show
  2552. ++ grep 192.168.0.3
  2553. ++ awk '{print $4}'
  2554. ++ awk 'END {print}'
  2555. + IPV4_ADDRESS=192.168.0.3/24
  2556. awk '{print $3}' <<< "${route}"
  2557. ++ awk '{print $3}'
  2558. + IPv4gw=192.168.0.1
  2559. + getStaticIPv4Settings
  2560. + local ipSettingsCorrect
  2561. + whiptail --backtitle 'Calibrating network interface' --title 'Static IP Address' --yesno 'Do you want to use your current network settings as a                                                                                                                                                                             static address?
  2562.           IP address:    192.168.0.3/24
  2563.           Gateway:       192.168.0.1' 20 70
  2564. + whiptail --msgbox --backtitle 'IP information' --title 'FYI: IP Conflict' 'It is possible your router could still try to assign this IP to a de                                                                                                                                                                            vice, which would cause a conflict.  But in most cases the router is smart enough to not do that.
  2565. If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
  2566. It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address.' 20 70
  2567. + setStaticIPv4
  2568. + local IFCFG_FILE
  2569. + local IPADDR
  2570. + local CIDR
  2571. + [[ -f /etc/dhcpcd.conf ]]
  2572. + grep -q 192.168.0.3/24 /etc/dhcpcd.conf
  2573. + echo -e '  [i] Static IP already configured'
  2574.   [i] Static IP already configured
  2575. + [[ -n true ]]
  2576. + useIPv6dialog
  2577. + IPV6_ADDRESSES=($(ip -6 address | grep 'scope global' | awk '{print $2}'))
  2578. ip -6 address | grep 'scope global' | awk '{print $2}'
  2579. ++ ip -6 address
  2580. ++ grep 'scope global'
  2581. ++ awk '{print $2}'
  2582. + for i in '"${IPV6_ADDRESSES[@]}"'
  2583. testIPv6 "$i"
  2584. ++ testIPv6 2600:8800:4580:3883:cbd7:8c0a:faf2:757b/64
  2585. cut -f1 -d":" <<< "$1"
  2586. +++ cut -f1 -d:
  2587. ++ first=2600
  2588. ++ value1=38
  2589. ++ value2=0
  2590. ++ ((  (value1&254)==252  ))
  2591. ++ ((  (value1&112)==32  ))
  2592. ++ echo GUA
  2593. ++ ((  (value1)==254  ))
  2594. + result=GUA
  2595. + [[ GUA == \U\L\A ]]
  2596. + [[ GUA == \G\U\A ]]
  2597. + GUA_ADDRESS=2600:8800:4580:3883:cbd7:8c0a:faf2:757b
  2598. + [[ ! -z '' ]]
  2599. + [[ ! -z 2600:8800:4580:3883:cbd7:8c0a:faf2:757b ]]
  2600. + echo -e '  [i] Found IPv6 GUA address, using it for blocking IPv6 ads'
  2601.   [i] Found IPv6 GUA address, using it for blocking IPv6 ads
  2602. + IPV6_ADDRESS=2600:8800:4580:3883:cbd7:8c0a:faf2:757b
  2603. + [[ ! -z 2600:8800:4580:3883:cbd7:8c0a:faf2:757b ]]
  2604. + whiptail --msgbox --backtitle IPv6... --title 'IPv6 Supported' '2600:8800:4580:3883:cbd7:8c0a:faf2:757b will be used to block ads.' 20 70
  2605. + echo -e '  [i] IPv4 address: 192.168.0.3/24'
  2606.   [i] IPv4 address: 192.168.0.3/24
  2607. + echo -e '  [i] IPv6 address: 2600:8800:4580:3883:cbd7:8c0a:faf2:757b'
  2608.   [i] IPv6 address: 2600:8800:4580:3883:cbd7:8c0a:faf2:757b
  2609. + [[ ! -n true ]]
  2610. + setAdminFlag
  2611. + local WebToggleCommand
  2612. + local WebChooseOptions
  2613. + local WebChoices
  2614. + WebToggleCommand=(whiptail --separate-output --radiolist "Do you wish to install the web admin interface?" ${r} ${c} 6)
  2615. + WebChooseOptions=("On (Recommended)" "" on Off "" off)
  2616. "${WebToggleCommand[@]}" "${WebChooseOptions[@]}" 2>&1 >/dev/tty
  2617. ++ whiptail --separate-output --radiolist 'Do you wish to install the web admin interface?' 20 70 6 'On (Recommended)' '' on Off '' off
  2618. + WebChoices='On (Recommended)'
  2619. + case ${WebChoices} in
  2620. + echo -e '  [i] Web Interface On'
  2621.   [i] Web Interface On
  2622. + INSTALL_WEB=true
  2623. + setLogging
  2624. + local LogToggleCommand
  2625. + local LogChooseOptions
  2626. + local LogChoices
  2627. + LogToggleCommand=(whiptail --separate-output --radiolist "Do you want to log queries?\\n (Disabling will render graphs on the Admin page useles                                                                                                                                                                            s):" ${r} ${c} 6)
  2628. + LogChooseOptions=("On (Recommended)" "" on Off "" off)
  2629. "${LogToggleCommand[@]}" "${LogChooseOptions[@]}" 2>&1 >/dev/tty
  2630. ++ whiptail --separate-output --radiolist 'Do you want to log queries?\n (Disabling will render graphs on the Admin page useless):' 20 70 6 'On (                                                                                                                                                                            Recommended)' '' on Off '' off
  2631. + LogChoices='On (Recommended)'
  2632. + case ${LogChoices} in
  2633. + echo -e '  [i] Logging On.'
  2634.   [i] Logging On.
  2635. + QUERY_LOGGING=true
  2636. + clone_or_update_repos
  2637. + [[ false == true ]]
  2638. + getGitFiles /etc/.pihole https://github.com/pi-hole/pi-hole.git
  2639. + local directory=/etc/.pihole
  2640. + local remoteRepo=https://github.com/pi-hole/pi-hole.git
  2641. + local 'str=Check for existing repository in /etc/.pihole'
  2642. + echo -ne '  [i] Check for existing repository in /etc/.pihole...'
  2643.   [i] Check for existing repository in /etc/.pihole...+ is_repo /etc/.pihole
  2644. + local directory=/etc/.pihole
  2645. + local curdir
  2646. + local rc
  2647. + curdir=/etc/dnsmasq.d
  2648. + [[ -d /etc/.pihole ]]
  2649. + rc=1
  2650. + cd /etc/dnsmasq.d
  2651. + return 1
  2652. + echo -e '\r\033[K  [\e[1;31m✗\e[0m] Check for existing repository in /etc/.pihole'
  2653.   [✗] Check for existing repository in /etc/.pihole
  2654. + make_repo /etc/.pihole https://github.com/pi-hole/pi-hole.git
  2655. + local directory=/etc/.pihole
  2656. + local remoteRepo=https://github.com/pi-hole/pi-hole.git
  2657. + str='Clone https://github.com/pi-hole/pi-hole.git into /etc/.pihole'
  2658. + echo -ne '  [i] Clone https://github.com/pi-hole/pi-hole.git into /etc/.pihole...'
  2659.   [i] Clone https://github.com/pi-hole/pi-hole.git into /etc/.pihole...+ [[ -d /etc/.pihole ]]
  2660. + git clone -q --depth 1 https://github.com/pi-hole/pi-hole.git /etc/.pihole
  2661. + return 128
  2662. + echo -e '\n  \e[1;31mError: Could not update local repository. Contact support.\e[0m'
  2663.  
  2664.   Error: Could not update local repository. Contact support.
  2665. + exit 1
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top