# Packages required for the Web admin interface (stored as an array)
# Packages required for the Web admin interface (stored as an array)
@ -419,32 +427,74 @@ select_rpm_php(){
rpm -q ${REMI_PKG}&> /dev/null ||rc=$?
rpm -q ${REMI_PKG}&> /dev/null ||rc=$?
if[[$rc -ne 0]];then
if[[$rc -ne 0]];then
# The PHP version available via default repositories is older than version 7
# The PHP version available via default repositories is older than version 7
if ! whiptail --defaultno --title "PHP 7 Update (recommended)" --yesno "PHP 7.x is recommended for both security and language features.\\nWould you like to install PHP7 via Remi's RPM repository?\\n\\nSee: https://rpms.remirepo.net for more information""${r}""${c}";then
dialog --no-shadow --clear \
# User decided to NOT update PHP from REMI, attempt to install the default available PHP version
--title "PHP 7 Update (recommended)"\
printf" %b User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use.\\n""${INFO}"
--defaultno \
: # continue with unsupported php version
--yesno "PHP 7.x is recommended for both security and language features. \
else
\\nWould you like to install PHP7 via Remi's RPM repository? \
printf" %b Remi's RPM repository has been enabled for PHP7\\n""${TICK}"
# trigger an install/update of PHP to ensure previous version of PHP is updated from REMI
if"${PKG_INSTALL[@]}""php-cli"&> /dev/null;then
printf" %b PHP7 installed/updated via Remi's RPM repository\\n""${TICK}"
else
printf" %b There was a problem updating to PHP7 via Remi's RPM repository\\n""${CROSS}"
exit1
fi
;;
# User chose not to install PHP 7 via Remi's RPM repository
"${DIALOG_CANCEL}")
# User decided to NOT update PHP from REMI, attempt to install the default available PHP version
printf" %b User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use.\\n""${INFO}"
;;
# User closed the dialog window
"${DIALOG_ESC}")
printf" %b Escape pressed, exiting installer at Remi dialog window\\n""${CROSS}"
exit1
exit1
fi
;;
fi
esac
fi# Warn user of unsupported version of Fedora or CentOS
if ! whiptail --defaultno --title "Unsupported RPM based distribution" --yesno "Would you like to continue installation on an unsupported RPM based distribution?\\n\\nPlease ensure the following packages have been installed manually:\\n\\n- lighttpd\\n- lighttpd-fastcgi\\n- PHP version 7+""${r}""${c}";then
printf" %b Aborting installation due to unsupported RPM based distribution\\n""${CROSS}"
exit
else
printf" %b Continuing installation with unsupported RPM based distribution\\n""${INFO}"
fi
fi
# Warn user of unsupported version of Fedora or CentOS
dialog --no-shadow --clear \
--title "Unsupported RPM based distribution"\
--defaultno \
--no-button "Exit"\
--yes-button "Continue"\
--yesno "Would you like to continue installation on an unsupported RPM based distribution? \
\\n\\nPlease ensure the following packages have been installed manually: \
\\n\\n- lighttpd\\n- lighttpd-fastcgi\\n- PHP version 7+"\
"${r}""${c}"
result=$?
case${result} in
# User chose to continue installation on an unsupported RPM based distribution
"${DIALOG_OK}")
printf" %b User opted to continue installation on an unsupported RPM based distribution.\\n""${INFO}"
;;
# User chose not to continue installation on an unsupported RPM based distribution
"${DIALOG_CANCEL}")
printf" %b User opted not to continue installation on an unsupported RPM based distribution.\\n""${INFO}"
exit1
;;
"${DIALOG_ESC}")
printf" %b Escape pressed, exiting installer at unsupported RPM based distribution dialog window\\n""${CROSS}"
exit1
;;
esac
fi
fi
fi
fi
}
}
@ -636,40 +686,46 @@ get_available_interfaces() {
# A function for displaying the dialogs the user sees when first running the installer
# A function for displaying the dialogs the user sees when first running the installer
welcomeDialogs(){
welcomeDialogs(){
# Display the welcome dialog using an appropriately sized window via the calculation conducted earlier in the script
# Display the welcome dialog using an appropriately sized window via the calculation conducted earlier in the script
whiptail --msgbox --backtitle "Welcome" --title "Pi-hole automated installer""\\n\\nThis installer will transform your device into a network-wide ad blocker!""${r}""${c}"
dialog --no-shadow --clear \
--backtitle "Welcome"\
# Request that users donate if they enjoy the software since we all work on it in our free time
--title "Pi-hole Automated Installer"\
whiptail --msgbox --backtitle "Plea" --title "Free and open source""\\n\\nThe Pi-hole is free, but powered by your donations: https://pi-hole.net/donate/""${r}""${c}"
--msgbox "\\n\\nThis installer will transform your device into a network-wide ad blocker!"\
"${r}""${c}"\
# Explain the need for a static address
--and-widget \
if whiptail --defaultno --backtitle "Initiating network interface" --title "Static IP Needed" --yesno "\\n\\nThe Pi-hole is a SERVER so it needs a STATIC IP ADDRESS to function properly.
--backtitle "Support Pi-hole"\
--title "Open Source Software"\
IMPORTANT: If you have not already done so, you must ensure that this device has a static IP. Either through DHCP reservation, or by manually assigning one. Depending on your operating system, there are many ways to achieve this.
--msgbox "\\n\\nThe Pi-hole is free, but powered by your donations: https://pi-hole.net/donate/"\
"${r}""${c}"\
Choose yes to indicate that you have understood this message, and wish to continue" "${r}" "${c}"; then
--and-widget \
#Nothing to do, continue
--colors \
echo
--backtitle "Initiating network interface"\
else
--title "Static IP Needed"\
printf" %b Installer exited at static IP message.\\n""${INFO}"
--no-button "Exit" --yes-button "Continue"\
exit1
--defaultno \
fi
--yesno "\\n\\nThe Pi-hole is a SERVER so it needs a STATIC IP ADDRESS to function properly.\\n\\n \
\\Zb\\Z1IMPORTANT:\\Zn If you have not already done so, you must ensure that this device has a static IP.\\n \
Depending on your operating system, there are many ways to achieve this, through DHCP reservation, or by manually assigning one.\\n\\n \
Please continue when the static addressing has been configured."\
"${r}""${c}"
result=$?
case"${result}" in
"${DIALOG_CANCEL}"|"${DIALOG_ESC}")
printf" %b Installer exited at static IP message.\\n""${INFO}"
exit1
;;
esac
}
}
# A function that lets the user pick an interface to use with Pi-hole
# A function that lets the user pick an interface to use with Pi-hole
chooseInterface(){
chooseInterface(){
# Turn the available interfaces into an array so it can be used with a whiptail dialog
# Turn the available interfaces into a string so it can be used with dialog
localinterfacesArray=()
localinterfacesList
# Number of available interfaces
# Number of available interfaces
local interfaceCount
local interfaceCount
# Whiptail variable storage
local chooseInterfaceCmd
# Temporary Whiptail options storage
local chooseInterfaceOptions
# Loop sentinel variable
localfirstLoop=1
# Find out how many interfaces are available to choose from
# POSIX compliant way to get the number of elements in an array
printf" %b Using interface: %s\\n""${INFO}""${PIHOLE_INTERFACE}"
fi
fi
}
}
@ -789,57 +844,102 @@ getStaticIPv4Settings() {
local ipSettingsCorrect
local ipSettingsCorrect
local DHCPChoice
local DHCPChoice
# Ask if the user wants to use DHCP settings as their static IP
# Ask if the user wants to use DHCP settings as their static IP
# This is useful for users that are using DHCP reservations; then we can just use the information gathered via our functions
# This is useful for users that are using DHCP reservations; we can use the information gathered
DHCPChoice=$(whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --menu --separate-output "Do you want to use your current network settings as a static address? \\n
--menu "Do you want to use your current network settings as a static address?\\n \
"No""Set static IP using custom values"\
IP address: ${IPV4_ADDRESS}\\n \
"Skip""I will set a static IP later, or have already done so" 3>&2 2>&1 1>&3)||\
Gateway: ${IPv4gw}\\n"\
{printf" %bCancel was selected, exiting installer%b\\n""${COL_LIGHT_RED}""${COL_NC}";exit 1;}
"${r}""${c}"3\
"Yes""Set static IP using current values"\
case${DHCPChoice} in
"No""Set static IP using custom values"\
"Yes")
"Skip""I will set a static IP later, or have already done so")
# If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
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.
result=$?
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
case${result} in
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}"
"${DIALOG_CANCEL}"|"${DIALOG_ESC}")
# Nothing else to do since the variables are already set above
printf" %bCancel was selected, exiting installer%b\\n""${COL_LIGHT_RED}""${COL_NC}"
setDHCPCD
exit1
;;
;;
esac
"No")
# Otherwise, we need to ask the user to input their desired settings.
case${DHCPChoice} in
# Start by getting the IPv4 address (pre-filling it with info gathered from DHCP)
"Skip")
# Start a loop to let the user enter their information with the chance to go back and edit it if necessary
return
until[["${ipSettingsCorrect}"= True ]];do
;;
"Yes")
# Ask for the IPv4 address
# If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
# Prompt the user to enter custom upstream servers
# Prompt the user to enter custom upstream servers
piholeDNS=$(whiptail --backtitle "Specify Upstream DNS Provider(s)" --inputbox "Enter your desired upstream DNS provider(s), separated by a comma. If you want to specify a port other than 53, separate it with a hash.\\n\\nFor example '8.8.8.8, 8.8.4.4' or '127.0.0.1#5335'""${r}""${c}""${prePopulate}" 3>&1 1>&2 2>&3)||\
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}
dialog --no-shadow --clear \
--title "Invalid IP Address(es)"\
--backtitle "Invalid IP"\
--msgbox "\\nOne or both of the entered IP addresses were invalid. Please try again. \
printf" %bCancel was selected, exiting installer%b\\n""${COL_LIGHT_RED}""${COL_NC}"
exit1
;;
esac
# set the variables back to nothing,
# set the variables back to nothing,
if[["${PIHOLE_DNS_1}"=="${strInvalid}"]];then
if[["${PIHOLE_DNS_1}"=="${strInvalid}"]];then
PIHOLE_DNS_1=""
PIHOLE_DNS_1=""
@ -988,12 +1122,25 @@ setDNS() {
# and continue the loop.
# and continue the loop.
DNSSettingsCorrect=False
DNSSettingsCorrect=False
else
else
# Otherwise, show the DNS setting to the user, and break the loop if they confirm them.
dialog --no-shadow --clear \
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
--backtitle "Specify Upstream DNS Provider(s)"\
DNSSettingsCorrect=True
--title "Upstream DNS Provider(s)"\
else
--yesno "Are these settings correct?\\n\\tDNS Server 1:\\t${PIHOLE_DNS_1}\\n\\tDNS Server 2:\\t${PIHOLE_DNS_2}"\
DNSSettingsCorrect=False
"${r}""${c}"
fi
result=$?
case${result} in
"${DIALOG_OK}")
DNSSettingsCorrect=True
;;
"${DIALOG_CANCEL}")
DNSSettingsCorrect=False
;;
"${DIALOG_ESC}")
printf" %bEscape pressed, exiting installer at DNS Settings%b\\n""${COL_LIGHT_RED}""${COL_NC}"
exit1
;;
esac
fi
fi
done
done
else
else
@ -1023,106 +1170,122 @@ setDNS() {
# Allow the user to enable/disable logging
# Allow the user to enable/disable logging
setLogging(){
setLogging(){
# Local, named variables
# Ask the user if they want to enable logging
local LogToggleCommand
dialog --no-shadow --clear \
local LogChooseOptions
--backtitle "Pihole Installation"\
local LogChoices
--title "Enable Logging"\
--yesno "\\n\\nWould you like to enable query logging?"\
# Ask if the user wants to log queries
"${r}""${c}"
LogToggleCommand=(whiptail --separate-output --radiolist "Do you want to log queries?""${r}""${c}" 6)
# The default selection is on
result=$?
LogChooseOptions=("On (Recommended)""" on
case${result} in
Off "" off)
"${DIALOG_OK}")
# Get the user's choice
# If they chose yes,
LogChoices=$("${LogToggleCommand[@]}""${LogChooseOptions[@]}" 2>&1 >/dev/tty)||(printf" %bCancel was selected, exiting installer%b\\n""${COL_LIGHT_RED}""${COL_NC}"&&exit 1)
printf" %b Query Logging on.\\n""${INFO}"
case${LogChoices} in
# If it's on,
"On (Recommended)")
printf" %b Logging On.\\n""${INFO}"
# set the GLOBAL variable setting to true
QUERY_LOGGING=true
QUERY_LOGGING=true
;;
;;
# Otherwise, it's off,
"${DIALOG_CANCEL}")
Off)
# If they chose no,
printf" %b Logging Off.\\n""${INFO}"
printf" %b Query Logging off.\\n""${INFO}"
# set the GLOBAL variable setting to false
QUERY_LOGGING=false
QUERY_LOGGING=false
;;
;;
"${DIALOG_ESC}")
# User pressed <ESC>
printf" %bEscape pressed, exiting installer at Query Logging choice.%b\\n""${COL_LIGHT_RED}""${COL_NC}"
# Function to ask the user if they want to install the dashboard
# Function to ask the user if they want to install the dashboard
setAdminFlag(){
setAdminFlag(){
# Local, named variables
local WebToggleCommand
local WebChooseOptions
local WebChoices
# Similar to the logging function, ask what the user wants
# Similar to the logging function, ask what the user wants
WebToggleCommand=(whiptail --separate-output --radiolist "Do you wish to install the web admin interface?""${r}""${c}" 6)
dialog --no-shadow --clear \
# with the default being enabled
--backtitle "Pihole Installation"\
WebChooseOptions=("On (Recommended)""" on
--title "Admin Web Interface"\
Off "" off)
--yesno "\\n\\nDo you want to install the Admin Web Interface?"\
WebChoices=$("${WebToggleCommand[@]}""${WebChooseOptions[@]}" 2>&1 >/dev/tty)||(printf" %bCancel was selected, exiting installer%b\\n""${COL_LIGHT_RED}""${COL_NC}"&&exit 1)
"${r}""${c}"
# Depending on their choice
case${WebChoices} in
result=$?
"On (Recommended)")
case${result} in
printf" %b Web Interface On\\n""${INFO}"
"${DIALOG_OK}")
# Set it to true
# If they chose yes,
printf" %b Installing Admin Web Interface\\n""${INFO}"
# Set the flag to install the web interface
INSTALL_WEB_INTERFACE=true
INSTALL_WEB_INTERFACE=true
;;
;;
Off)
"${DIALOG_CANCEL}")
printf" %b Web Interface Off\\n""${INFO}"
# If they chose no,
# or false
printf" %b Not installing Admin Web Interface\\n""${INFO}"
# Set the flag to not install the web interface
INSTALL_WEB_INTERFACE=false
INSTALL_WEB_INTERFACE=false
# Deselect the web server as well, since it is obsolete then
INSTALL_WEB_SERVER=false
INSTALL_WEB_SERVER=false
;;
;;
"${DIALOG_ESC}")
# User pressed <ESC>
printf" %bEscape pressed, exiting installer at Admin Web Interface choice.%b\\n""${COL_LIGHT_RED}""${COL_NC}"
exit1
;;
esac
esac
# If the user wants to install the Web admin interface (i.e. it has not been deselected above)
# If the user wants to install the Web admin interface (i.e. it has not been deselected above)
if[["${INSTALL_WEB_SERVER}"==true]];then
if[["${INSTALL_WEB_INTERFACE}"==true]];then
# Get list of required PHP modules, excluding base package (common) and handler (cgi)
# Get list of required PHP modules, excluding base package (common) and handler (cgi)
local i php_modules
local i php_modules
for i in "${PIHOLE_WEB_DEPS[@]}";do[[$i=='php'* &&$i != *'-common'&&$i != *'-cgi']]&&php_modules+="${i#*-}";done
for i in "${PIHOLE_WEB_DEPS[@]}";do[[$i=='php'* &&$i != *'-common'&&$i != *'-cgi']]&&php_modules+="${i#*-}";done
WebToggleCommand=(whiptail --separate-output --radiolist "Do you wish to install the web server (lighttpd) and required PHP modules?\\n\\nNB: If you disable this, and, do not have an existing web server and required PHP modules (${php_modules# }) installed, the web interface will not function. Additionally the web server user needs to be member of the \"pihole\" group for full functionality.""${r}""${c}" 6)
dialog --no-shadow --clear \
# Enable as default and recommended option
--backtitle "Pi-hole Installation"\
WebChooseOptions=("On (Recommended)""" on
--title "Web Server"\
Off "" off)
--yesno "\\n\\nA web server is required for the Admin Web Interface. \
WebChoices=$("${WebToggleCommand[@]}""${WebChooseOptions[@]}" 2>&1 >/dev/tty)||(printf" %bCancel was selected, exiting installer%b\\n""${COL_LIGHT_RED}""${COL_NC}"&&exit 1)
\\n\\nDo you want to install lighttpd and the required PHP modules? \
# Depending on their choice
\\n\\nNB: If you disable this, and, do not have an existing web server \
case${WebChoices} in
and required PHP modules (${php_modules# }) installed, the web interface \
"On (Recommended)")
will not function. Additionally the web server user needs to be member of \
printf" %b Web Server On\\n""${INFO}"
the \"pihole\" group for full functionality."\
# set it to true, as clearly seen below.
"${r}""${c}"
result=$?
case${result} in
"${DIALOG_OK}")
# If they chose yes,
printf" %b Installing lighttpd\\n""${INFO}"
# Set the flag to install the web server
INSTALL_WEB_SERVER=true
INSTALL_WEB_SERVER=true
;;
;;
Off)
"${DIALOG_CANCEL}")
printf" %b Web Server Off\\n""${INFO}"
# If they chose no,
# or false
printf" %b Not installing lighttpd\\n""${INFO}"
# Set the flag to not install the web server
INSTALL_WEB_SERVER=false
INSTALL_WEB_SERVER=false
;;
;;
"${DIALOG_ESC}")
# User pressed <ESC>
printf" %bEscape pressed, exiting installer at web server choice.%b\\n""${COL_LIGHT_RED}""${COL_NC}"
exit1
;;
esac
esac
fi
fi
}
}
@ -1133,18 +1296,33 @@ chooseBlocklists() {
if[[ -f "${adlistFile}"]];then
if[[ -f "${adlistFile}"]];then
mv "${adlistFile}""${adlistFile}.old"
mv "${adlistFile}""${adlistFile}.old"
fi
fi
# Let user select (or not) blocklists via a checklist
# Let user select (or not) blocklists
cmd=(whiptail --separate-output --checklist "Pi-hole relies on third party lists in order to block ads.\\n\\nYou can use the suggestion below, and/or add your own after installation\\n\\nTo deselect the suggested list, use spacebar""${r}""${c}" 5)
dialog --no-shadow --clear \
# In an array, show the options available (all off by default):
# Check if /etc/dnsmasq.conf is from pi-hole. If so replace with an original and install new in .d directory
# Check if /etc/dnsmasq.conf is from pi-hole. If so replace with an original and install new in .d directory
@ -1940,14 +2110,14 @@ Your Admin Webpage login password is ${pwstring}"
fi
fi
# Final completion message to user
# Final completion message to user
whiptail --msgbox --backtitle "Make it so." --title "Installation Complete!""Configure your devices to use the Pi-hole as their DNS server using:
dialog --no-shadow --clear \
--title "Installation Complete!"\
IPv4: ${IPV4_ADDRESS%/*}
--msgbox "Configure your devices to use the Pi-hole as their DNS server using: \
IPv6: ${IPV6_ADDRESS:-"Not Configured"}
\\n\\nIPv4: ${IPV4_ADDRESS%/*}\
\\nIPv6: ${IPV6_ADDRESS:-"Not Configured"}\
If you have not done so already, the above IP should be set to static.
\\nIf you have not done so already, the above IP should be set to static.\
\\n${additional}"
${additional}" "${r}" "${c}"
"${r}""${c}"
}
}
update_dialogs(){
update_dialogs(){
@ -1967,20 +2137,32 @@ update_dialogs() {
opt2b="Resets Pi-hole and allows re-selecting settings."
opt2b="Resets Pi-hole and allows re-selecting settings."
# Display the information to the user
# Display the information to the user
UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\\n\\nWe have detected an existing install.\\n\\nPlease choose from the following options: \\n($strAdd)""${r}""${c}"2\