2015-11-25 21:43:59 +00:00
#!/usr/bin/env bash
2017-07-26 17:00:08 +00:00
# shellcheck disable=SC1090
2015-10-28 22:29:34 +00:00
# Pi-hole: A black hole for Internet advertisements
2018-01-20 13:29:38 +00:00
# (c) 2017-2018 Pi-hole, LLC (https://pi-hole.net)
2017-02-22 17:55:20 +00:00
# Network-wide ad blocking via your own hardware.
#
2017-07-26 17:00:08 +00:00
# Installs and Updates Pi-hole
2015-12-06 14:31:49 +00:00
#
2017-02-22 17:55:20 +00:00
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
2015-10-28 22:29:34 +00:00
# pi-hole.net/donate
2015-06-14 03:14:21 +00:00
#
2017-07-07 00:25:56 +00:00
# Install with this command (from your Linux machine):
2015-06-14 03:14:21 +00:00
#
2018-01-20 13:29:38 +00:00
# curl -sSL https://install.pi-hole.net | bash
2015-06-14 03:14:21 +00:00
2017-07-07 00:25:56 +00:00
# -e option instructs bash to immediately exit if any command [1] has a non-zero exit status
# We do not want users to end up with a partially working install, so we exit the script
# instead of continuing the installation with something broken
2016-10-10 09:24:03 +00:00
set -e
2017-07-07 00:25:56 +00:00
2015-10-28 22:29:34 +00:00
######## VARIABLES #########
2017-07-07 00:25:56 +00:00
# For better maintainability, we store as much information that can change in variables
2018-02-07 05:45:23 +00:00
# This allows us to make a change in one place that can propagate to all instances of the variable
2017-07-07 00:25:56 +00:00
# These variables should all be GLOBAL variables, written in CAPS
# Local variables will be in lowercase and will exist only within functions
# It's still a work in progress, so you may see some variance in this guideline until it is complete
2018-01-20 13:55:48 +00:00
# Location for final installation log storage
2018-01-20 14:20:06 +00:00
installLogLoc = /etc/pihole/install.log
2017-07-07 00:25:56 +00:00
# This is an important file as it contains information specific to the machine it's being installed on
2016-08-21 16:57:11 +00:00
setupVars = /etc/pihole/setupVars.conf
2017-07-07 00:25:56 +00:00
# Pi-hole uses lighttpd as a Web server, and this is the config file for it
2017-07-26 17:00:08 +00:00
# shellcheck disable=SC2034
2016-12-04 20:30:59 +00:00
lighttpdConfig = /etc/lighttpd/lighttpd.conf
2017-07-07 00:25:56 +00:00
# This is a file used for the colorized output
2017-06-21 11:49:05 +00:00
coltable = /opt/pihole/COL_TABLE
2015-10-31 14:15:57 +00:00
2017-07-07 00:25:56 +00:00
# We store several other folders and
2016-01-24 03:31:12 +00:00
webInterfaceGitUrl = "https://github.com/pi-hole/AdminLTE.git"
webInterfaceDir = "/var/www/html/admin"
piholeGitUrl = "https://github.com/pi-hole/pi-hole.git"
2016-11-02 07:14:25 +00:00
PI_HOLE_LOCAL_REPO = "/etc/.pihole"
2018-02-07 05:45:23 +00:00
# These are the names of pi-holes files, stored in an array
2017-01-15 04:16:27 +00:00
PI_HOLE_FILES = ( chronometer list piholeDebug piholeLogFlush setupLCD update version gravity uninstall webpage)
2017-07-07 00:25:56 +00:00
# This folder is where the Pi-hole scripts will be installed
2017-01-09 07:01:18 +00:00
PI_HOLE_INSTALL_DIR = "/opt/pihole"
2016-08-19 21:31:11 +00:00
useUpdateVars = false
2016-01-23 00:13:16 +00:00
2018-04-17 08:50:25 +00:00
adlistFile = "/etc/pihole/adlists.list"
2017-07-07 00:25:56 +00:00
# Pi-hole needs an IP address; to begin, these variables are empty since we don't know what the IP is until
# this script can run
2016-11-01 09:45:22 +00:00
IPV4_ADDRESS = ""
IPV6_ADDRESS = ""
2017-07-07 00:25:56 +00:00
# By default, query logging is enabled and the dashboard is set to be installed
2016-11-01 16:46:54 +00:00
QUERY_LOGGING = true
2018-04-15 01:08:16 +00:00
INSTALL_WEB_INTERFACE = true
2017-01-28 14:38:54 +00:00
2018-06-01 08:20:40 +00:00
if [ -z " ${ USER } " ] ; then
USER = " $( id -un) "
fi
2016-10-10 12:45:37 +00:00
2017-09-30 20:34:38 +00:00
# Find the rows and columns will default to 80x24 if it can not be detected
2016-11-02 12:17:28 +00:00
screen_size = $( stty size 2>/dev/null || echo 24 80)
2017-01-01 14:32:49 +00:00
rows = $( echo " ${ screen_size } " | awk '{print $1}' )
columns = $( echo " ${ screen_size } " | awk '{print $2}' )
2015-10-28 22:29:34 +00:00
# Divide by two so the dialogs take up half of the screen, which looks nice.
r = $(( rows / 2 ))
c = $(( columns / 2 ))
2016-10-26 14:44:15 +00:00
# Unless the screen is tiny
r = $(( r < 20 ? 20 : r ))
c = $(( c < 70 ? 70 : c ))
2015-10-28 22:29:34 +00:00
2016-10-15 19:52:20 +00:00
######## Undocumented Flags. Shhh ########
2017-07-07 00:25:56 +00:00
# These are undocumented flags; some of which we can use when repairing an installation
# The runUnattended flag is one example of this
2016-10-15 19:43:03 +00:00
skipSpaceCheck = false
2016-10-15 20:12:13 +00:00
reconfigure = false
2016-10-15 19:43:03 +00:00
runUnattended = false
2018-04-15 01:08:16 +00:00
INSTALL_WEB_SERVER = true
# Check arguments for the undocumented flags
for var in " $@ " ; do
case " $var " in
"--reconfigure" ) reconfigure = true; ;
"--i_do_not_follow_recommendations" ) skipSpaceCheck = true; ;
"--unattended" ) runUnattended = true; ;
"--disable-install-webserver" ) INSTALL_WEB_SERVER = false; ;
esac
done
2016-10-15 19:43:03 +00:00
2017-07-07 00:25:56 +00:00
# If the color table file exists,
2017-07-26 17:00:08 +00:00
if [ [ -f " ${ coltable } " ] ] ; then
2017-07-07 00:25:56 +00:00
# source it
2017-06-21 11:49:05 +00:00
source ${ coltable }
2018-02-07 05:45:23 +00:00
# Otherwise,
2017-06-21 11:49:05 +00:00
else
2017-07-07 00:25:56 +00:00
# Set these values so the installer can still run in color
2017-06-21 11:49:05 +00:00
COL_NC = '\e[0m' # No Color
COL_LIGHT_GREEN = '\e[1;32m'
COL_LIGHT_RED = '\e[1;31m'
TICK = " [ ${ COL_LIGHT_GREEN } ✓ ${ COL_NC } ] "
CROSS = " [ ${ COL_LIGHT_RED } ✗ ${ COL_NC } ] "
INFO = "[i]"
2017-07-26 17:00:08 +00:00
# shellcheck disable=SC2034
2017-06-21 11:49:05 +00:00
DONE = " ${ COL_LIGHT_GREEN } done! ${ COL_NC } "
2017-07-26 17:00:08 +00:00
OVER = "\\r\\033[K"
2017-06-21 11:49:05 +00:00
fi
2017-07-07 00:25:56 +00:00
# A simple function that just echoes out our logo in ASCII format
# This lets users know that it is a Pi-hole, LLC product
2017-03-09 03:14:21 +00:00
show_ascii_berry( ) {
2017-06-21 11:49:05 +00:00
echo -e "
${ COL_LIGHT_GREEN } .; ; ,.
2017-03-09 03:14:21 +00:00
.ccccc:,.
:cccclll:. ..,,
:ccccclll. ; ooodc
' ccll:; ll .oooodc
.; cll.; ; looo:.
2017-06-21 11:49:05 +00:00
${ COL_LIGHT_RED } .. ',' .
2017-03-09 03:14:21 +00:00
.',,,,,,' .
.' ,,,,,,,,,,.
.' ,,,,,,,,,,,,....
....'' ',,,,,,,' .......
......... .... .........
.......... ..........
.......... ..........
......... .... .........
........,,,,,,,' ......
....' ,,,,,,,,,,,,.
.',,,,,,,,,' .
.',,,,,,' .
2017-06-21 11:49:05 +00:00
..'' ' .${ COL_NC }
2017-03-09 03:14:21 +00:00
"
}
2016-08-19 21:31:11 +00:00
# Compatibility
2017-01-21 20:34:47 +00:00
distro_check( ) {
2017-07-07 14:05:19 +00:00
# If apt-get is installed, then we know it's part of the Debian family
2016-12-27 19:53:23 +00:00
if command -v apt-get & > /dev/null; then
2017-07-07 00:25:56 +00:00
# Set some global variables here
# We don't set them earlier since the family might be Red Hat, so these values would be different
2017-03-03 10:52:49 +00:00
PKG_MANAGER = "apt-get"
2017-07-07 00:25:56 +00:00
# A variable to store the command used to update the package cache
2017-05-09 20:11:28 +00:00
UPDATE_PKG_CACHE = " ${ PKG_MANAGER } update "
2017-07-07 00:25:56 +00:00
# An array for something...
2017-01-09 07:01:18 +00:00
PKG_INSTALL = ( ${ PKG_MANAGER } --yes --no-install-recommends install)
2016-11-02 12:17:28 +00:00
# grep -c will return 1 retVal on 0 matches, block this throwing the set -e with an OR TRUE
PKG_COUNT = " ${ PKG_MANAGER } -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true "
2017-07-07 00:25:56 +00:00
# Some distros vary slightly so these fixes for dependencies may apply
# Debian 7 doesn't have iproute2 so if the dry run install is successful,
2017-01-15 02:23:52 +00:00
if ${ PKG_MANAGER } install --dry-run iproute2 > /dev/null 2>& 1; then
2017-07-07 00:25:56 +00:00
# we can install it
2017-01-15 02:23:52 +00:00
iproute_pkg = "iproute2"
2017-07-07 00:25:56 +00:00
# Otherwise,
2017-01-15 02:23:52 +00:00
else
2017-07-07 00:25:56 +00:00
# use iproute
2017-01-15 02:23:52 +00:00
iproute_pkg = "iproute"
fi
2017-07-07 00:25:56 +00:00
# We prefer the php metapackage if it's there
2017-01-15 02:23:52 +00:00
if ${ PKG_MANAGER } install --dry-run php > /dev/null 2>& 1; then
phpVer = "php"
2017-07-07 00:25:56 +00:00
# If not,
2017-01-15 02:23:52 +00:00
else
2017-07-07 00:25:56 +00:00
# fall back on the php5 packages
2017-01-15 02:23:52 +00:00
phpVer = "php5"
fi
2017-08-16 15:27:50 +00:00
# We also need the correct version for `php-sqlite` (which differs across distros)
if ${ PKG_MANAGER } install --dry-run ${ phpVer } -sqlite3 > /dev/null 2>& 1; then
phpSqlite = "sqlite3"
else
phpSqlite = "sqlite"
fi
2017-12-11 04:51:54 +00:00
# Since our install script is so large, we need several other programs to successfully get a machine provisioned
2017-07-07 00:25:56 +00:00
# These programs are stored in an array so they can be looped through later
2017-02-27 20:21:59 +00:00
INSTALLER_DEPS = ( apt-utils dialog debconf dhcpcd5 git ${ iproute_pkg } whiptail)
2017-07-07 00:25:56 +00:00
# Pi-hole itself has several dependencies that also need to be installed
2018-04-19 21:31:43 +00:00
PIHOLE_DEPS = ( bc cron curl dnsutils iputils-ping lsof netcat psmisc sudo unzip wget idn2 sqlite3 libcap2-bin dns-root-data resolvconf)
2017-07-07 00:25:56 +00:00
# The Web dashboard has some that also need to be installed
# It's useful to separate the two since our repos are also setup as "Core" code and "Web" code
2017-08-16 15:27:50 +00:00
PIHOLE_WEB_DEPS = ( lighttpd ${ phpVer } -common ${ phpVer } -cgi ${ phpVer } -${ phpSqlite } )
2017-07-07 00:25:56 +00:00
# The Web server user,
2016-11-02 12:17:28 +00:00
LIGHTTPD_USER = "www-data"
2017-07-07 00:25:56 +00:00
# group,
2016-11-02 12:17:28 +00:00
LIGHTTPD_GROUP = "www-data"
2017-07-07 00:25:56 +00:00
# and config file
2018-03-18 00:38:34 +00:00
LIGHTTPD_CFG = "lighttpd.conf.debian"
2016-11-02 12:17:28 +00:00
2017-08-17 18:43:07 +00:00
# A function to check...
test_dpkg_lock( ) {
# An iterator used for counting loop iterations
i = 0
# fuser is a program to show which processes use the named files, sockets, or filesystems
# So while the command is true
while fuser /var/lib/dpkg/lock >/dev/null 2>& 1 ; do
# Wait half a second
sleep 0.5
# and increase the iterator
( ( i = i+1) )
done
# Always return success, since we only return if there is no
# lock (anymore)
return 0
}
2017-03-03 10:28:35 +00:00
2017-07-07 00:25:56 +00:00
# If apt-get is not found, check for rpm to see if it's a Red Hat family OS
2016-12-27 19:53:23 +00:00
elif command -v rpm & > /dev/null; then
2017-07-07 00:25:56 +00:00
# Then check if dnf or yum is the package manager
2016-12-27 19:53:23 +00:00
if command -v dnf & > /dev/null; then
2016-11-02 12:17:28 +00:00
PKG_MANAGER = "dnf"
else
PKG_MANAGER = "yum"
fi
2016-12-27 20:37:19 +00:00
2018-03-18 00:38:34 +00:00
# Fedora and family update cache on every PKG_INSTALL call, no need for a separate update.
2016-12-27 18:59:24 +00:00
UPDATE_PKG_CACHE = ":"
2017-01-17 21:00:17 +00:00
PKG_INSTALL = ( ${ PKG_MANAGER } install -y)
2016-11-02 12:17:28 +00:00
PKG_COUNT = " ${ PKG_MANAGER } check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l "
2017-02-27 20:21:59 +00:00
INSTALLER_DEPS = ( dialog git iproute net-tools newt procps-ng)
2018-03-07 22:23:05 +00:00
PIHOLE_DEPS = ( bc bind-utils cronie curl findutils nmap-ncat sudo unzip wget libidn2 psmisc)
2017-08-16 14:56:39 +00:00
PIHOLE_WEB_DEPS = ( lighttpd lighttpd-fastcgi php php-common php-cli php-pdo)
2018-01-08 04:21:04 +00:00
# EPEL (https://fedoraproject.org/wiki/EPEL) is required for lighttpd on CentOS
if grep -qi 'centos' /etc/redhat-release; then
2016-12-27 20:59:53 +00:00
INSTALLER_DEPS = ( " ${ INSTALLER_DEPS [@] } " "epel-release" ) ;
2016-11-02 12:17:28 +00:00
fi
LIGHTTPD_USER = "lighttpd"
LIGHTTPD_GROUP = "lighttpd"
2018-03-18 00:38:34 +00:00
LIGHTTPD_CFG = "lighttpd.conf.fedora"
2016-11-02 12:17:28 +00:00
2017-11-05 09:05:25 +00:00
# If neither apt-get or rmp/dnf are found
2016-04-26 04:51:00 +00:00
else
2017-07-07 00:25:56 +00:00
# it's not an OS we can support,
2017-06-21 11:49:05 +00:00
echo -e " ${ CROSS } OS distribution not supported "
2017-07-07 00:25:56 +00:00
# so exit the installer
2016-11-02 12:17:28 +00:00
exit
2016-04-26 04:51:00 +00:00
fi
2017-01-21 20:34:47 +00:00
}
2015-11-08 23:21:02 +00:00
2017-07-07 00:25:56 +00:00
# A function for checking if a folder is a git repository
2016-11-02 07:14:25 +00:00
is_repo( ) {
2017-12-11 04:51:54 +00:00
# Use a named, local variable instead of the vague $1, which is the first argument passed to this function
2017-07-07 00:25:56 +00:00
# These local variables should always be lowercase
2016-11-02 13:34:57 +00:00
local directory = " ${ 1 } "
2017-07-10 19:12:30 +00:00
# A local variable for the current directory
2017-01-01 06:34:20 +00:00
local curdir
2017-07-07 00:25:56 +00:00
# A variable to store the return code
2017-01-01 06:34:20 +00:00
local rc
2017-07-07 00:25:56 +00:00
# Assign the current directory variable by using pwd
2017-01-01 06:34:20 +00:00
curdir = " ${ PWD } "
2017-07-07 00:25:56 +00:00
# If the first argument passed to this function is a directory,
2017-01-01 06:34:20 +00:00
if [ [ -d " ${ directory } " ] ] ; then
2017-07-07 00:25:56 +00:00
# move into the directory
2017-01-01 06:34:20 +00:00
cd " ${ directory } "
2017-07-07 00:25:56 +00:00
# Use git to check if the folder is a repo
# git -C is not used here to support git versions older than 1.8.4
2017-01-01 06:34:20 +00:00
git status --short & > /dev/null || rc = $?
2017-07-07 00:25:56 +00:00
# If the command was not successful,
2016-12-23 01:57:13 +00:00
else
2017-07-07 00:25:56 +00:00
# Set a non-zero return code if directory does not exist
2017-01-01 06:34:20 +00:00
rc = 1
2016-12-23 01:57:13 +00:00
fi
2017-07-07 00:25:56 +00:00
# Move back into the directory the user started in
2017-01-01 06:34:20 +00:00
cd " ${ curdir } "
2017-07-07 00:25:56 +00:00
# Return the code; if one is not set, return 0
2017-01-01 06:34:20 +00:00
return " ${ rc :- 0 } "
2016-11-02 07:14:25 +00:00
}
2017-07-07 00:25:56 +00:00
# A function to clone a repo
2016-11-02 07:14:25 +00:00
make_repo( ) {
2017-07-07 00:25:56 +00:00
# Set named variables for better readability
2016-11-02 13:34:57 +00:00
local directory = " ${ 1 } "
2016-12-21 01:22:57 +00:00
local remoteRepo = " ${ 2 } "
2017-07-07 00:25:56 +00:00
# The message to display when this function is running
2017-06-21 11:49:05 +00:00
str = " Clone ${ remoteRepo } into ${ directory } "
2017-07-07 00:25:56 +00:00
# Display the message and use the color table to preface the message with an "info" indicator
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# If the directory exists,
2017-01-01 06:34:20 +00:00
if [ [ -d " ${ directory } " ] ] ; then
2017-07-07 00:25:56 +00:00
# delete everything in it so git can clone into it
2017-01-01 06:34:20 +00:00
rm -rf " ${ directory } "
fi
2017-07-07 00:25:56 +00:00
# Clone the repo and return the return code from this command
2017-01-01 06:34:20 +00:00
git clone -q --depth 1 " ${ remoteRepo } " " ${ directory } " & > /dev/null || return $?
2017-07-07 00:25:56 +00:00
# Show a colored message showing it's status
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2017-07-07 00:25:56 +00:00
# Always return 0? Not sure this is correct
2017-01-01 06:34:20 +00:00
return 0
2016-11-02 07:14:25 +00:00
}
2017-07-07 00:25:56 +00:00
# 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
2016-11-02 07:14:25 +00:00
update_repo( ) {
2017-07-07 00:25:56 +00:00
# Use named, local variables
# As you can see, these are the same variable names used in the last function,
# but since they are local, their scope does not go beyond this function
# This helps prevent the wrong value from being assigned if you were to set the variable as a GLOBAL one
2016-12-21 01:22:57 +00:00
local directory = " ${ 1 } "
2017-01-29 01:32:42 +00:00
local curdir
2017-01-01 08:07:10 +00:00
2017-07-07 00:25:56 +00:00
# A variable to store the message we want to display;
# Again, it's useful to store these in variables in case we need to reuse or change the message;
# we only need to make one change here
2017-06-21 11:49:05 +00:00
local str = " Update repo in ${ 1 } "
2017-07-07 00:25:56 +00:00
# Make sure we know what directory we are in so we can move back into it
2017-01-29 01:32:42 +00:00
curdir = " ${ PWD } "
2017-07-07 00:25:56 +00:00
# Move into the directory that was passed as an argument
2017-01-29 01:32:42 +00:00
cd " ${ directory } " & > /dev/null || return 1
2017-07-07 00:25:56 +00:00
# Let the user know what's happening
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# Stash any local commits as they conflict with our working code
2017-01-29 01:32:42 +00:00
git stash --all --quiet & > /dev/null || true # Okay for stash failure
2017-07-01 12:08:17 +00:00
git clean --quiet --force -d || true # Okay for already clean directory
2017-07-07 00:25:56 +00:00
# Pull the latest commits
2017-01-29 01:32:42 +00:00
git pull --quiet & > /dev/null || return $?
2017-07-07 00:25:56 +00:00
# Show a completion message
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2017-12-11 04:51:54 +00:00
# Move back into the original directory
2017-01-29 01:32:42 +00:00
cd " ${ curdir } " & > /dev/null || return 1
2017-01-01 08:07:10 +00:00
return 0
2016-11-02 07:14:25 +00:00
}
2017-07-07 00:25:56 +00:00
# A function that combines the functions previously made
2016-11-02 07:14:25 +00:00
getGitFiles( ) {
2017-07-07 00:25:56 +00:00
# Setup named variables for the git repos
# We need the directory
2016-12-21 01:22:57 +00:00
local directory = " ${ 1 } "
2017-07-07 00:25:56 +00:00
# as well as the repo URL
2016-12-21 01:22:57 +00:00
local remoteRepo = " ${ 2 } "
2017-12-11 04:51:54 +00:00
# A local variable containing the message to be displayed
2017-06-21 11:49:05 +00:00
local str = " Check for existing repository in ${ 1 } "
2017-07-07 00:25:56 +00:00
# Show the message
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# Check if the directory is a repository
2016-12-21 01:22:57 +00:00
if is_repo " ${ directory } " ; then
2017-07-07 00:25:56 +00:00
# Show that we're checking it
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2017-07-07 00:25:56 +00:00
# Update the repo, returning an error message on failure
2017-07-26 17:00:08 +00:00
update_repo " ${ directory } " || { echo -e " \\n ${ COL_LIGHT_RED } Error: Could not update local repository. Contact support. ${ COL_NC } " ; exit 1; }
2017-07-07 00:25:56 +00:00
# If it's not a .git repo,
2016-12-21 01:22:57 +00:00
else
2017-07-07 00:25:56 +00:00
# Show an error
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ CROSS } ${ str } "
2017-12-11 04:51:54 +00:00
# Attempt to make the repository, showing an error on failure
2017-07-26 17:00:08 +00:00
make_repo " ${ directory } " " ${ remoteRepo } " || { echo -e " \\n ${ COL_LIGHT_RED } Error: Could not update local repository. Contact support. ${ COL_NC } " ; exit 1; }
2016-12-21 01:22:57 +00:00
fi
2017-07-07 00:25:56 +00:00
# echo a blank line
2017-06-21 11:49:05 +00:00
echo ""
2017-07-07 00:25:56 +00:00
# and return success?
2017-01-01 06:34:20 +00:00
return 0
2016-11-02 07:14:25 +00:00
}
2017-07-07 00:25:56 +00:00
# Reset a repo to get rid of any local changed
2017-05-22 21:43:52 +00:00
resetRepo( ) {
2017-12-11 04:51:54 +00:00
# Use named variables for arguments
2017-05-22 21:43:52 +00:00
local directory = " ${ 1 } "
2017-07-07 00:25:56 +00:00
# Move into the directory
2017-05-22 21:43:52 +00:00
cd " ${ directory } " & > /dev/null || return 1
2017-12-11 04:51:54 +00:00
# Store the message in a variable
2017-06-21 11:49:05 +00:00
str = " Resetting repository within ${ 1 } ... "
2017-07-07 00:25:56 +00:00
# Show the message
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } ${ str } "
2017-07-07 00:25:56 +00:00
# Use git to remove the local changes
2017-05-22 21:43:52 +00:00
git reset --hard & > /dev/null || return $?
2017-07-07 00:25:56 +00:00
# And show the status
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2017-07-07 00:25:56 +00:00
# Returning success anyway?
2017-01-01 06:34:20 +00:00
return 0
2016-11-02 07:14:25 +00:00
}
2017-07-07 00:25:56 +00:00
# We need to know the IPv4 information so we can effectively setup the DNS server
# Without this information, we won't know where to Pi-hole will be found
2016-10-10 12:45:37 +00:00
find_IPv4_information( ) {
2017-07-07 00:25:56 +00:00
# Named, local variables
2017-01-09 02:04:24 +00:00
local route
2017-07-07 00:25:56 +00:00
# Find IP used to route to outside world by checking the the route to Google's public DNS server
2017-01-09 02:04:24 +00:00
route = $( ip route get 8.8.8.8)
2017-07-07 00:25:56 +00:00
# Use awk to strip out just the interface device as it is used in future commands
2017-01-09 02:04:24 +00:00
IPv4dev = $( awk '{for (i=1; i<=NF; i++) if ($i~/dev/) print $(i+1)}' <<< " ${ route } " )
2017-07-07 00:25:56 +00:00
# Get just the IP address
2017-01-19 21:50:42 +00:00
IPv4bare = $( awk '{print $7}' <<< " ${ route } " )
2017-07-07 00:25:56 +00:00
# Append the CIDR notation to the IP address
2017-01-19 21:50:42 +00:00
IPV4_ADDRESS = $( ip -o -f inet addr show | grep " ${ IPv4bare } " | awk '{print $4}' | awk 'END {print}' )
2017-07-07 00:25:56 +00:00
# Get the default gateway (the way to reach the Internet)
2017-01-09 02:04:24 +00:00
IPv4gw = $( awk '{print $3}' <<< " ${ route } " )
2016-05-01 02:27:38 +00:00
}
2017-07-07 00:25:56 +00:00
# Get available interfaces that are UP
2016-10-10 10:16:22 +00:00
get_available_interfaces( ) {
2017-07-07 00:25:56 +00:00
# There may be more than one so it's all stored in a variable
2017-03-16 05:05:48 +00:00
availableInterfaces = $( ip --oneline link show up | grep -v "lo" | awk '{print $2}' | cut -d':' -f1 | cut -d'@' -f1)
2016-10-10 10:16:22 +00:00
}
2015-11-10 00:33:32 +00:00
2017-07-07 00:25:56 +00:00
# A function for displaying the dialogs the user sees when first running the installer
2016-01-27 06:11:38 +00:00
welcomeDialogs( ) {
2017-12-11 04:51:54 +00:00
# Display the welcome dialog using an appropriately sized window via the calculation conducted earlier in the script
2017-07-26 17:00:08 +00:00
whiptail --msgbox --backtitle "Welcome" --title "Pi-hole automated installer" "\\n\\nThis installer will transform your device into a network-wide ad blocker!" ${ r } ${ c }
2016-01-28 09:25:00 +00:00
2017-07-07 00:25:56 +00:00
# Request that users donate if they enjoy the software since we all work on it in our free time
2017-07-26 17:00:08 +00:00
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 }
2016-01-28 09:25:00 +00:00
2016-12-21 01:22:57 +00:00
# Explain the need for a static address
2017-07-26 17:00:08 +00:00
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.
2016-06-10 22:47:27 +00:00
2016-08-19 21:31:11 +00:00
In the next section, you can choose to use your current network settings ( DHCP) or to manually edit them." ${ r } ${ c }
2015-11-08 23:21:02 +00:00
}
2017-07-07 00:25:56 +00:00
# We need to make sure there is enough space before installing, so there is a function to check this
2016-02-10 15:34:06 +00:00
verifyFreeDiskSpace( ) {
2016-08-12 11:44:45 +00:00
2016-12-21 01:22:57 +00:00
# 50MB is the minimum space needed (45MB install (includes web admin bootstrap/jquery libraries etc) + 5MB one day of logs.)
# - Fourdee: Local ensures the variable is only created, and accessible within this function/void. Generally considered a "good" coding practice for non-global variables.
2017-06-21 11:49:05 +00:00
local str = "Disk space check"
2017-12-11 04:51:54 +00:00
# Required space in KB
2016-12-21 01:22:57 +00:00
local required_free_kilobytes = 51200
2017-07-07 00:25:56 +00:00
# Calculate existing free space on this machine
2017-07-26 17:00:08 +00:00
local existing_free_kilobytes
existing_free_kilobytes = $( df -Pk | grep -m1 '\/$' | awk '{print $4}' )
2016-12-21 01:22:57 +00:00
2017-07-07 00:25:56 +00:00
# If the existing space is not an integer,
2016-12-21 01:22:57 +00:00
if ! [ [ " ${ existing_free_kilobytes } " = ~ ^( [ 0-9] ) +$ ] ] ; then
2017-07-07 00:25:56 +00:00
# show an error that we can't determine the free space
2017-06-21 11:49:05 +00:00
echo -e " ${ CROSS } ${ str }
Unknown free disk space!
We were unable to determine available free disk space on this system.
You may override this check, however, it is not recommended
The option '${COL_LIGHT_RED}--i_do_not_follow_recommendations${COL_NC}' can override this
e.g: curl -L https://install.pi-hole.net | bash /dev/stdin ${ COL_LIGHT_RED } <option>${ COL_NC } "
2017-07-07 00:25:56 +00:00
# exit with an error code
2016-12-21 01:22:57 +00:00
exit 1
2017-07-07 00:25:56 +00:00
# If there is insufficient free disk space,
2017-07-26 17:00:08 +00:00
elif [ [ " ${ existing_free_kilobytes } " -lt " ${ required_free_kilobytes } " ] ] ; then
2017-07-07 00:25:56 +00:00
# show an error message
2017-06-21 11:49:05 +00:00
echo -e " ${ CROSS } ${ str }
Your system disk appears to only have ${ existing_free_kilobytes } KB free
It is recommended to have a minimum of ${ required_free_kilobytes } KB to run the Pi-hole"
2017-07-07 00:25:56 +00:00
# if the vcgencmd command exists,
2017-06-21 11:49:05 +00:00
if command -v vcgencmd & > /dev/null; then
2017-07-07 00:25:56 +00:00
# it's probably a Raspbian install, so show a message about expanding the filesystem
2017-06-21 11:49:05 +00:00
echo " If this is a new install you may need to expand your disk
Run 'sudo raspi-config' , and choose the 'expand file system' option
After rebooting, run this installation again
e.g: curl -L https://install.pi-hole.net | bash"
fi
2017-07-07 00:25:56 +00:00
# Show there is not enough free space
2017-07-26 17:00:08 +00:00
echo -e " \\n ${ COL_LIGHT_RED } Insufficient free space, exiting... ${ COL_NC } "
2017-07-07 00:25:56 +00:00
# and exit with an error
2016-12-21 01:22:57 +00:00
exit 1
2017-07-07 00:25:56 +00:00
# Otherwise,
2017-06-21 11:49:05 +00:00
else
2017-07-07 00:25:56 +00:00
# Show that we're running a disk space check
2017-06-21 11:49:05 +00:00
echo -e " ${ TICK } ${ str } "
2016-12-21 01:22:57 +00:00
fi
2016-02-10 15:34:06 +00:00
}
2017-07-07 00:25:56 +00:00
# A function that let's the user pick an interface to use with Pi-hole
2016-01-27 06:11:38 +00:00
chooseInterface( ) {
2016-12-21 01:22:57 +00:00
# Turn the available interfaces into an array so it can be used with a whiptail dialog
local interfacesArray = ( )
# Number of available interfaces
local interfaceCount
# Whiptail variable storage
local chooseInterfaceCmd
# Temporary Whiptail options storage
local chooseInterfaceOptions
# Loop sentinel variable
local firstLoop = 1
# Find out how many interfaces are available to choose from
interfaceCount = $( echo " ${ availableInterfaces } " | wc -l)
2017-01-09 02:46:15 +00:00
2017-07-07 00:25:56 +00:00
# If there is one interface,
2017-07-26 17:00:08 +00:00
if [ [ " ${ interfaceCount } " -eq 1 ] ] ; then
2017-07-07 00:25:56 +00:00
# Set it as the interface to use since there is no other option
2017-01-15 02:23:52 +00:00
PIHOLE_INTERFACE = " ${ availableInterfaces } "
2017-07-07 00:25:56 +00:00
# Otherwise,
2017-01-15 02:23:52 +00:00
else
2017-07-07 00:25:56 +00:00
# While reading through the available interfaces
2017-01-15 02:23:52 +00:00
while read -r line; do
2017-07-07 00:25:56 +00:00
# use a variable to set the option as OFF to begin with
2017-01-15 02:23:52 +00:00
mode = "OFF"
2017-07-07 00:25:56 +00:00
# If it's the first loop,
2017-07-26 17:00:08 +00:00
if [ [ " ${ firstLoop } " -eq 1 ] ] ; then
2017-07-07 00:25:56 +00:00
# set this as the interface to use (ON)
2017-01-15 02:23:52 +00:00
firstLoop = 0
mode = "ON"
fi
2017-07-07 00:25:56 +00:00
# Put all these interfaces into an array
2017-01-15 02:23:52 +00:00
interfacesArray += ( " ${ line } " "available" " ${ mode } " )
2017-07-07 00:25:56 +00:00
# Feed the available interfaces into this while loop
2017-01-15 02:23:52 +00:00
done <<< " ${ availableInterfaces } "
2017-07-07 00:25:56 +00:00
# The whiptail command that will be run, stored in a variable
2017-01-15 02:23:52 +00:00
chooseInterfaceCmd = ( whiptail --separate-output --radiolist "Choose An Interface (press space to select)" ${ r } ${ c } ${ interfaceCount } )
2017-07-07 00:25:56 +00:00
# Now run the command using the interfaces saved into the array
2017-01-15 02:23:52 +00:00
chooseInterfaceOptions = $( " ${ chooseInterfaceCmd [@] } " " ${ interfacesArray [@] } " 2>& 1 >/dev/tty) || \
2017-12-11 04:51:54 +00:00
# If the user chooses Cancel, exit
2017-06-21 11:49:05 +00:00
{ echo -e " ${ COL_LIGHT_RED } Cancel was selected, exiting installer ${ COL_NC } " ; exit 1; }
2017-07-07 00:25:56 +00:00
# For each interface
2017-01-15 02:23:52 +00:00
for desiredInterface in ${ chooseInterfaceOptions } ; do
2017-07-07 00:25:56 +00:00
# Set the one the user selected as the interface to use
2017-01-15 02:23:52 +00:00
PIHOLE_INTERFACE = ${ desiredInterface }
2017-07-07 00:25:56 +00:00
# and show this information to the user
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } Using interface: $PIHOLE_INTERFACE "
2017-01-15 02:23:52 +00:00
done
fi
2016-10-10 12:45:37 +00:00
}
2016-03-06 05:16:23 +00:00
2017-07-07 00:25:56 +00:00
# This lets us prefer ULA addresses over GUA
# This caused problems for some users when their ISP changed their IPv6 addresses
2017-06-02 21:01:48 +00:00
# See https://github.com/pi-hole/pi-hole/issues/1473#issuecomment-301745953
testIPv6( ) {
2017-07-07 00:25:56 +00:00
# first will contain fda2 (ULA)
2017-06-02 21:01:48 +00:00
first = " $( cut -f1 -d":" <<< " $1 " ) "
2017-07-07 00:25:56 +00:00
# value1 will contain 253 which is the decimal value corresponding to 0xfd
2017-12-06 22:31:12 +00:00
value1 = $(( ( 0 x$first ) / 256 ))
2017-07-07 00:25:56 +00:00
# will contain 162 which is the decimal value corresponding to 0xa2
2017-12-06 22:31:12 +00:00
value2 = $(( ( 0 x$first ) % 256 ))
2017-07-07 00:25:56 +00:00
# the ULA test is testing for fc00::/7 according to RFC 4193
2017-12-06 22:57:05 +00:00
if ( ( ( value1& 254) = = 252 ) ) ; then
2017-12-06 22:31:12 +00:00
echo "ULA"
fi
2017-07-07 00:25:56 +00:00
# the GUA test is testing for 2000::/3 according to RFC 4291
2017-12-06 22:57:05 +00:00
if ( ( ( value1& 112) = = 32 ) ) ; then
2017-12-06 22:31:12 +00:00
echo "GUA"
fi
2017-07-07 00:25:56 +00:00
# the LL test is testing for fe80::/10 according to RFC 4193
2017-12-06 22:57:05 +00:00
if ( ( ( value1) = = 254 ) ) && ( ( ( value2& 192) = = 128 ) ) ; then
2017-12-06 22:31:12 +00:00
echo "Link-local"
fi
2017-06-02 21:01:48 +00:00
}
2017-07-07 00:25:56 +00:00
# A dialog for showing the user about IPv6 blocking
2016-10-10 12:45:37 +00:00
useIPv6dialog( ) {
2017-06-02 21:01:48 +00:00
# Determine the IPv6 address used for blocking
IPV6_ADDRESSES = ( $( ip -6 address | grep 'scope global' | awk '{print $2}' ) )
2017-07-07 00:25:56 +00:00
# For each address in the array above, determine the type of IPv6 address it is
2017-06-02 21:01:48 +00:00
for i in " ${ IPV6_ADDRESSES [@] } " ; do
2017-07-07 00:25:56 +00:00
# Check if it's ULA, GUA, or LL by using the function created earlier
2017-06-02 21:01:48 +00:00
result = $( testIPv6 " $i " )
2017-07-07 00:25:56 +00:00
# If it's a ULA address, use it and store it as a global variable
2017-06-29 01:18:52 +00:00
[ [ " ${ result } " = = "ULA" ] ] && ULA_ADDRESS = " ${ i %/* } "
2017-07-07 00:25:56 +00:00
# If it's a GUA address, we can still use it si store it as a global variable
2017-06-29 01:18:52 +00:00
[ [ " ${ result } " = = "GUA" ] ] && GUA_ADDRESS = " ${ i %/* } "
2017-06-02 21:01:48 +00:00
done
# Determine which address to be used: Prefer ULA over GUA or don't use any if none found
2017-07-07 00:25:56 +00:00
# If the ULA_ADDRESS contains a value,
2017-06-02 21:01:48 +00:00
if [ [ ! -z " ${ ULA_ADDRESS } " ] ] ; then
2017-07-07 00:25:56 +00:00
# set the IPv6 address to the ULA address
2017-06-02 21:01:48 +00:00
IPV6_ADDRESS = " ${ ULA_ADDRESS } "
2017-07-07 00:25:56 +00:00
# Show this info to the user
2017-07-26 17:00:08 +00:00
echo -e " ${ INFO } Found IPv6 ULA address, using it for blocking IPv6 ads "
2017-07-07 00:25:56 +00:00
# Otherwise, if the GUA_ADDRESS has a value,
2017-06-02 21:01:48 +00:00
elif [ [ ! -z " ${ GUA_ADDRESS } " ] ] ; then
2017-07-07 00:25:56 +00:00
# Let the user know
2017-07-26 17:00:08 +00:00
echo -e " ${ INFO } Found IPv6 GUA address, using it for blocking IPv6 ads "
2017-07-07 00:25:56 +00:00
# And assign it to the global variable
2017-06-02 21:01:48 +00:00
IPV6_ADDRESS = " ${ GUA_ADDRESS } "
2017-07-07 00:25:56 +00:00
# If none of those work,
2017-06-02 21:01:48 +00:00
else
2017-07-07 00:25:56 +00:00
# explain that IPv6 blocking will not be used
2017-07-26 17:00:08 +00:00
echo -e " ${ INFO } Unable to find IPv6 ULA/GUA address, IPv6 adblocking will not be enabled "
2017-07-07 00:25:56 +00:00
# So set the variable to be empty
2017-06-02 21:01:48 +00:00
IPV6_ADDRESS = ""
fi
2016-12-24 23:26:05 +00:00
2017-07-07 00:25:56 +00:00
# If the IPV6_ADDRESS contains a value
2016-12-24 23:26:05 +00:00
if [ [ ! -z " ${ IPV6_ADDRESS } " ] ] ; then
2017-07-07 00:25:56 +00:00
# Display that IPv6 is supported and will be used
2016-12-24 23:26:05 +00:00
whiptail --msgbox --backtitle "IPv6..." --title "IPv6 Supported" " $IPV6_ADDRESS will be used to block ads. " ${ r } ${ c }
fi
2015-11-10 00:33:32 +00:00
}
2017-07-07 00:25:56 +00:00
# A function to check if we should use IPv4 and/or IPv6 for blocking ads
2016-01-27 06:11:38 +00:00
use4andor6( ) {
2017-07-07 00:25:56 +00:00
# Named local variables
2016-12-21 01:22:57 +00:00
local useIPv4
local useIPv6
2017-07-07 00:25:56 +00:00
# Let use select IPv4 and/or IPv6 via a checklist
2016-12-21 01:22:57 +00:00
cmd = ( whiptail --separate-output --checklist "Select Protocols (press space to select)" ${ r } ${ c } 2)
2017-07-07 00:25:56 +00:00
# In an array, show the options available:
# IPv4 (on by default)
2016-12-21 01:22:57 +00:00
options = ( IPv4 "Block ads over IPv4" on
2017-07-07 00:25:56 +00:00
# or IPv6 (on by default if available)
2016-12-21 01:22:57 +00:00
IPv6 "Block ads over IPv6" on)
2017-07-07 00:25:56 +00:00
# In a variable, show the choices available; exit if Cancel is selected
2017-06-21 11:49:05 +00:00
choices = $( " ${ cmd [@] } " " ${ options [@] } " 2>& 1 >/dev/tty) || { echo -e " ${ COL_LIGHT_RED } Cancel was selected, exiting installer ${ COL_NC } " ; exit 1; }
2017-07-07 00:25:56 +00:00
# For each choice available,
2017-01-09 02:46:15 +00:00
for choice in ${ choices }
do
2017-07-07 00:25:56 +00:00
# Set the values to true
2017-01-09 02:46:15 +00:00
case ${ choice } in
IPv4 ) useIPv4 = true; ;
IPv6 ) useIPv6 = true; ;
esac
done
2017-07-07 00:25:56 +00:00
# If IPv4 is to be used,
2017-07-26 17:00:08 +00:00
if [ [ " ${ useIPv4 } " ] ] ; then
2017-07-07 00:25:56 +00:00
# Run our function to get the information we need
2017-01-09 02:46:15 +00:00
find_IPv4_information
getStaticIPv4Settings
setStaticIPv4
fi
2017-07-07 00:25:56 +00:00
# If IPv6 is to be used,
2017-07-26 17:00:08 +00:00
if [ [ " ${ useIPv6 } " ] ] ; then
2017-07-07 00:25:56 +00:00
# Run our function to get this information
2017-01-09 02:46:15 +00:00
useIPv6dialog
fi
2017-07-07 00:25:56 +00:00
# Echo the information to the user
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } IPv4 address: ${ IPV4_ADDRESS } "
echo -e " ${ INFO } IPv6 address: ${ IPV6_ADDRESS } "
2017-07-07 00:25:56 +00:00
# If neither protocol is selected,
2017-07-26 17:00:08 +00:00
if [ [ ! " ${ useIPv4 } " ] ] && [ [ ! " ${ useIPv6 } " ] ] ; then
2017-07-07 00:25:56 +00:00
# Show an error in red
2017-06-21 11:49:05 +00:00
echo -e " ${ COL_LIGHT_RED } Error: Neither IPv4 or IPv6 selected ${ COL_NC } "
2017-07-07 00:25:56 +00:00
# and exit with an error
2016-12-21 01:22:57 +00:00
exit 1
fi
2015-11-10 00:33:32 +00:00
}
2015-11-08 23:21:02 +00:00
2017-07-07 00:25:56 +00:00
#
2016-01-27 06:11:38 +00:00
getStaticIPv4Settings( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2017-01-09 07:01:18 +00:00
local ipSettingsCorrect
2016-12-21 01:22:57 +00:00
# Ask if the user wants to use DHCP settings as their static IP
2017-07-07 00:25:56 +00:00
# This is useful for users that are using DHCP reservations; then we can just use the information gathered via our functions
2017-01-09 05:30:38 +00:00
if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno " Do you want to use your current network settings as a static address?
2016-12-21 01:22:57 +00:00
IP address: ${ IPV4_ADDRESS }
2017-01-09 05:30:38 +00:00
Gateway: ${ IPv4gw } " ${ r } ${ c } ; then
2016-12-21 01:22:57 +00:00
# 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.
2016-04-03 23:05:11 +00:00
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
2016-08-19 21:31:11 +00:00
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 }
2017-07-07 00:25:56 +00:00
# Nothing else to do since the variables are already set above
2016-12-21 01:22:57 +00:00
else
# Otherwise, we need to ask the user to input their desired settings.
# Start by getting the IPv4 address (pre-filling it with info gathered from DHCP)
# Start a loop to let the user enter their information with the chance to go back and edit it if necessary
2017-07-26 17:00:08 +00:00
until [ [ " ${ ipSettingsCorrect } " = True ] ] ; do
2017-01-09 02:46:15 +00:00
2016-12-21 01:22:57 +00:00
# Ask for the IPv4 address
2017-01-09 02:46:15 +00:00
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) || \
# Cancelling IPv4 settings window
2017-06-21 11:49:05 +00:00
{ ipSettingsCorrect = False; echo -e " ${ COL_LIGHT_RED } Cancel was selected, exiting installer ${ COL_NC } " ; exit 1; }
echo -e " ${ INFO } Your static IPv4 address: ${ IPV4_ADDRESS } "
2017-01-09 02:46:15 +00:00
2016-12-21 01:22:57 +00:00
# Ask for the gateway
2017-01-09 02:46:15 +00:00
IPv4gw = $( whiptail --backtitle "Calibrating network interface" --title "IPv4 gateway (router)" --inputbox "Enter your desired IPv4 default gateway" ${ r } ${ c } " ${ IPv4gw } " 3>& 1 1>& 2 2>& 3) || \
# Cancelling gateway settings window
2017-06-21 11:49:05 +00:00
{ ipSettingsCorrect = False; echo -e " ${ COL_LIGHT_RED } Cancel was selected, exiting installer ${ COL_NC } " ; exit 1; }
echo -e " ${ INFO } Your static IPv4 gateway: ${ IPv4gw } "
2017-01-09 02:46:15 +00:00
# Give the user a chance to review their settings before moving on
2017-01-09 05:30:38 +00:00
if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno " Are these settings correct?
2017-06-21 11:49:05 +00:00
IP address: ${ IPV4_ADDRESS }
Gateway: ${ IPv4gw } " ${ r } ${ c } ; then
2017-01-09 02:46:15 +00:00
# After that's done, the loop ends and we move on
ipSettingsCorrect = True
2016-12-21 01:22:57 +00:00
else
2017-01-09 02:46:15 +00:00
# If the settings are wrong, the loop continues
2016-12-21 01:22:57 +00:00
ipSettingsCorrect = False
fi
done
# End the if statement for DHCP vs. static
fi
2015-11-08 23:21:02 +00:00
}
2017-07-07 00:25:56 +00:00
# dhcpcd is very annoying,
2016-01-27 06:11:38 +00:00
setDHCPCD( ) {
2017-07-07 14:05:19 +00:00
# but we can append these lines to dhcpcd.conf to enable a static IP
2017-02-02 02:33:42 +00:00
echo " interface ${ PIHOLE_INTERFACE }
2016-12-21 01:22:57 +00:00
static ip_address = ${ IPV4_ADDRESS }
static routers = ${ IPv4gw }
2017-05-05 19:03:51 +00:00
static domain_name_servers = 127.0.0.1" | tee -a /etc/dhcpcd.conf >/dev/null
2015-10-31 14:11:29 +00:00
}
2016-01-27 06:11:38 +00:00
setStaticIPv4( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2016-12-21 01:22:57 +00:00
local IFCFG_FILE
local IPADDR
local CIDR
2017-07-07 00:25:56 +00:00
# For the Debian family, if dhcpcd.conf exists,
2017-07-26 17:00:08 +00:00
if [ [ -f "/etc/dhcpcd.conf" ] ] ; then
2017-07-07 00:25:56 +00:00
# check if the IP is already in the file
2016-12-21 01:22:57 +00:00
if grep -q " ${ IPV4_ADDRESS } " /etc/dhcpcd.conf; then
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } Static IP already configured "
2017-07-07 00:25:56 +00:00
# If it's not,
2016-12-21 01:22:57 +00:00
else
2017-07-07 00:25:56 +00:00
# set it using our function
2016-12-21 01:22:57 +00:00
setDHCPCD
2017-07-07 00:25:56 +00:00
# Then use the ip command to immediately set the new address
2016-12-21 01:22:57 +00:00
ip addr replace dev " ${ PIHOLE_INTERFACE } " " ${ IPV4_ADDRESS } "
2017-07-07 00:25:56 +00:00
# Also give a warning that the user may need to reboot their system
2017-06-21 11:49:05 +00:00
echo -e " ${ TICK } Set IP address to ${ IPV4_ADDRESS %/* }
2017-07-26 17:00:08 +00:00
You may need to restart after the install is complete"
2016-12-21 01:22:57 +00:00
fi
2017-07-07 00:25:56 +00:00
# If it's not Debian, check if it's the Fedora family by checking for the file below
2017-07-26 17:00:08 +00:00
elif [ [ -f " /etc/sysconfig/network-scripts/ifcfg- ${ PIHOLE_INTERFACE } " ] ] ; then
2017-07-07 00:25:56 +00:00
# If it exists,
2016-12-21 01:22:57 +00:00
IFCFG_FILE = /etc/sysconfig/network-scripts/ifcfg-${ PIHOLE_INTERFACE }
2017-11-05 20:28:44 +00:00
IPADDR = $( echo " ${ IPV4_ADDRESS } " | cut -f1 -d/)
2017-07-07 00:25:56 +00:00
# check if the desired IP is already set
2018-04-22 19:53:15 +00:00
if grep -Eq " ${ IPADDR } (\\b|\\/) " " ${ IFCFG_FILE } " ; then
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } Static IP already configured "
2017-07-07 00:25:56 +00:00
# Otherwise,
2016-12-21 01:22:57 +00:00
else
2017-07-07 00:25:56 +00:00
# Put the IP in variables without the CIDR notation
2016-12-21 01:22:57 +00:00
CIDR = $( echo " ${ IPV4_ADDRESS } " | cut -f2 -d/)
# Backup existing interface configuration:
cp " ${ IFCFG_FILE } " " ${ IFCFG_FILE } " .pihole.orig
2017-07-07 00:25:56 +00:00
# Build Interface configuration file using the GLOBAL variables we have
2016-12-21 01:22:57 +00:00
{
2017-04-03 15:29:57 +00:00
echo "# Configured via Pi-hole installer"
2016-12-21 01:22:57 +00:00
echo " DEVICE= $PIHOLE_INTERFACE "
echo "BOOTPROTO=none"
echo "ONBOOT=yes"
echo " IPADDR= $IPADDR "
echo " PREFIX= $CIDR "
echo " GATEWAY= $IPv4gw "
echo " DNS1= $PIHOLE_DNS_1 "
echo " DNS2= $PIHOLE_DNS_2 "
echo "USERCTL=no"
} > " ${ IFCFG_FILE } "
2017-07-07 00:25:56 +00:00
# Use ip to immediately set the new address
2016-12-21 01:22:57 +00:00
ip addr replace dev " ${ PIHOLE_INTERFACE } " " ${ IPV4_ADDRESS } "
2017-12-08 03:33:31 +00:00
# If NetworkMangler command line interface exists and ready to mangle,
if command -v nmcli & > /dev/null && nmcli general status & > /dev/null; then
2017-07-07 00:25:56 +00:00
# Tell NetworkManagler to read our new sysconfig file
2016-12-21 01:22:57 +00:00
nmcli con load " ${ IFCFG_FILE } " > /dev/null
fi
2017-07-07 00:25:56 +00:00
# Show a warning that the user may need to restart
2017-06-21 11:49:05 +00:00
echo -e " ${ TICK } Set IP address to ${ IPV4_ADDRESS %/* }
2017-07-26 17:00:08 +00:00
You may need to restart after the install is complete"
2016-12-21 01:22:57 +00:00
fi
2017-07-07 00:25:56 +00:00
# If all that fails,
2016-12-21 01:22:57 +00:00
else
2017-07-07 00:25:56 +00:00
# show an error and exit
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } Warning: Unable to locate configuration file to set static IPv4 address "
2016-12-21 01:22:57 +00:00
exit 1
fi
2015-12-06 10:40:30 +00:00
}
2017-07-07 00:25:56 +00:00
# Check an IP address to see if it is a valid one
2016-10-20 02:47:45 +00:00
valid_ip( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2016-12-21 01:22:57 +00:00
local ip = ${ 1 }
local stat = 1
2017-07-07 00:25:56 +00:00
# If the IP matches the format xxx.xxx.xxx.xxx,
2017-07-26 17:00:08 +00:00
if [ [ " ${ ip } " = ~ ^[ 0-9] { 1,3} \. [ 0-9] { 1,3} \. [ 0-9] { 1,3} \. [ 0-9] { 1,3} $ ] ] ; then
2017-12-11 04:51:54 +00:00
# Save the old Internal Field Separator in a variable
2016-12-21 01:22:57 +00:00
OIFS = $IFS
2017-07-07 00:25:56 +00:00
# and set the new one to a dot (period)
2016-12-21 01:22:57 +00:00
IFS = '.'
2017-07-07 00:25:56 +00:00
# Put the IP into an array
2016-12-21 01:22:57 +00:00
ip = ( ${ ip } )
2017-07-07 00:25:56 +00:00
# Restore the IFS to what it was
2016-12-21 01:22:57 +00:00
IFS = ${ OIFS }
2017-07-07 00:25:56 +00:00
## Evaluate each octet by checking if it's less than or equal to 255 (the max for each octet)
2017-07-26 17:00:08 +00:00
[ [ " ${ ip [0] } " -le 255 && " ${ ip [1] } " -le 255 \
&& " ${ ip [2] } " -le 255 && " ${ ip [3] } " -le 255 ] ]
2017-07-07 00:25:56 +00:00
# Save the exit code
2016-12-21 01:22:57 +00:00
stat = $?
fi
2017-07-07 00:25:56 +00:00
# Return the exit code
2016-12-21 01:22:57 +00:00
return ${ stat }
2016-02-20 17:33:20 +00:00
}
2017-07-07 00:25:56 +00:00
# A function to choose the upstream DNS provider(s)
2016-10-20 02:47:45 +00:00
setDNS( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2017-01-09 07:40:19 +00:00
local DNSSettingsCorrect
2017-07-07 00:25:56 +00:00
# In an array, list the available upstream providers
2017-01-22 00:14:05 +00:00
DNSChooseOptions = ( Google ""
OpenDNS ""
Level3 ""
Norton ""
Comodo ""
2017-02-18 12:42:13 +00:00
DNSWatch ""
2017-11-17 02:54:04 +00:00
Quad9 ""
2018-03-10 23:33:31 +00:00
FamilyShield ""
2018-04-01 22:59:08 +00:00
Cloudflare ""
2017-01-22 00:14:05 +00:00
Custom "" )
2017-07-07 00:25:56 +00:00
# In a whiptail dialog, show the options
2017-11-17 05:18:13 +00:00
DNSchoices = $( whiptail --separate-output --menu "Select Upstream DNS Provider. To use your own, select Custom." ${ r } ${ c } 7 \
2017-01-09 07:40:19 +00:00
" ${ DNSChooseOptions [@] } " 2>& 1 >/dev/tty) || \
2017-07-07 00:25:56 +00:00
# exit if Cancel is selected
2017-06-21 11:49:05 +00:00
{ echo -e " ${ COL_LIGHT_RED } Cancel was selected, exiting installer ${ COL_NC } " ; exit 1; }
2017-07-07 00:25:56 +00:00
# Display the selection
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } Using "
2017-07-07 00:25:56 +00:00
# Depending on the user's choice, set the GLOBAl variables to the IP of the respective provider
2017-01-09 07:40:19 +00:00
case ${ DNSchoices } in
Google)
2017-06-21 11:49:05 +00:00
echo "Google DNS servers"
2017-01-09 07:40:19 +00:00
PIHOLE_DNS_1 = "8.8.8.8"
PIHOLE_DNS_2 = "8.8.4.4"
; ;
OpenDNS)
2017-06-21 11:49:05 +00:00
echo "OpenDNS servers"
2017-01-09 07:40:19 +00:00
PIHOLE_DNS_1 = "208.67.222.222"
PIHOLE_DNS_2 = "208.67.220.220"
; ;
Level3)
2017-06-21 11:49:05 +00:00
echo "Level3 servers"
2017-01-09 07:40:19 +00:00
PIHOLE_DNS_1 = "4.2.2.1"
PIHOLE_DNS_2 = "4.2.2.2"
; ;
Norton)
2017-06-21 11:49:05 +00:00
echo "Norton ConnectSafe servers"
2017-01-09 07:40:19 +00:00
PIHOLE_DNS_1 = "199.85.126.10"
PIHOLE_DNS_2 = "199.85.127.10"
; ;
Comodo)
2017-06-21 11:49:05 +00:00
echo "Comodo Secure servers"
2017-01-09 07:40:19 +00:00
PIHOLE_DNS_1 = "8.26.56.26"
PIHOLE_DNS_2 = "8.20.247.20"
; ;
2017-02-18 12:42:13 +00:00
DNSWatch)
2017-06-21 11:49:05 +00:00
echo "DNS.WATCH servers"
2017-02-18 12:03:40 +00:00
PIHOLE_DNS_1 = "84.200.69.80"
PIHOLE_DNS_2 = "84.200.70.40"
; ;
2017-11-17 02:54:04 +00:00
Quad9)
echo "Quad9 servers"
PIHOLE_DNS_1 = "9.9.9.9"
2017-11-20 18:05:41 +00:00
PIHOLE_DNS_2 = "149.112.112.112"
2017-11-17 02:54:04 +00:00
; ;
2018-03-10 23:33:31 +00:00
FamilyShield)
echo "FamilyShield servers"
PIHOLE_DNS_1 = "208.67.222.123"
PIHOLE_DNS_2 = "208.67.220.123"
2018-03-10 23:36:47 +00:00
; ;
2018-04-01 22:59:08 +00:00
Cloudflare)
echo "Cloudflare servers"
PIHOLE_DNS_1 = "1.1.1.1"
PIHOLE_DNS_2 = "1.0.0.1"
; ;
2017-01-09 07:40:19 +00:00
Custom)
2017-07-07 00:25:56 +00:00
# Until the DNS settings are selected,
2017-07-26 17:00:08 +00:00
until [ [ " ${ DNSSettingsCorrect } " = True ] ] ; do
2017-07-07 00:25:56 +00:00
#
2017-01-09 07:40:19 +00:00
strInvalid = "Invalid"
2017-07-07 00:25:56 +00:00
# If the first
2017-07-26 17:00:08 +00:00
if [ [ ! " ${ PIHOLE_DNS_1 } " ] ] ; then
2017-07-07 00:25:56 +00:00
# and second upstream servers do not exist
2017-07-26 17:00:08 +00:00
if [ [ ! " ${ PIHOLE_DNS_2 } " ] ] ; then
2017-07-07 00:25:56 +00:00
#
2017-01-09 07:40:19 +00:00
prePopulate = ""
2017-07-07 00:25:56 +00:00
# Otherwise,
2017-01-09 07:40:19 +00:00
else
2017-07-07 00:25:56 +00:00
#
2017-01-09 07:40:19 +00:00
prePopulate = " , ${ PIHOLE_DNS_2 } "
2016-12-21 01:22:57 +00:00
fi
2017-07-07 00:25:56 +00:00
#
2017-07-26 17:00:08 +00:00
elif [ [ " ${ PIHOLE_DNS_1 } " ] ] && [ [ ! " ${ PIHOLE_DNS_2 } " ] ] ; then
2017-07-07 00:25:56 +00:00
#
2017-01-09 07:40:19 +00:00
prePopulate = " ${ PIHOLE_DNS_1 } "
2017-07-07 00:25:56 +00:00
#
2017-07-26 17:00:08 +00:00
elif [ [ " ${ PIHOLE_DNS_1 } " ] ] && [ [ " ${ PIHOLE_DNS_2 } " ] ] ; then
2017-07-07 00:25:56 +00:00
#
2017-01-09 07:40:19 +00:00
prePopulate = " ${ PIHOLE_DNS_1 } , ${ PIHOLE_DNS_2 } "
fi
2016-12-21 01:22:57 +00:00
2017-07-07 00:25:56 +00:00
# Dialog for the user to enter custom upstream servers
2017-12-11 04:51:54 +00:00
piholeDNS = $( whiptail --backtitle "Specify Upstream DNS Provider(s)" --inputbox "Enter your desired upstream DNS provider(s), separated by a comma.\\n\\nFor example '8.8.8.8, 8.8.4.4'" ${ r } ${ c } " ${ prePopulate } " 3>& 1 1>& 2 2>& 3) || \
2017-06-21 11:49:05 +00:00
{ echo -e " ${ COL_LIGHT_RED } Cancel was selected, exiting installer ${ COL_NC } " ; exit 1; }
2017-07-07 00:25:56 +00:00
#
2017-01-09 07:40:19 +00:00
PIHOLE_DNS_1 = $( echo " ${ piholeDNS } " | sed 's/[, \t]\+/,/g' | awk -F, '{print$1}' )
PIHOLE_DNS_2 = $( echo " ${ piholeDNS } " | sed 's/[, \t]\+/,/g' | awk -F, '{print$2}' )
2017-07-07 00:25:56 +00:00
# If the IP is valid,
2017-07-26 17:00:08 +00:00
if ! valid_ip " ${ PIHOLE_DNS_1 } " || [ [ ! " ${ PIHOLE_DNS_1 } " ] ] ; then
2017-07-07 00:25:56 +00:00
# store it in the variable so we can use it
2017-01-09 07:40:19 +00:00
PIHOLE_DNS_1 = ${ strInvalid }
fi
2017-07-07 00:25:56 +00:00
# Do the same for the secondary server
2017-07-26 17:00:08 +00:00
if ! valid_ip " ${ PIHOLE_DNS_2 } " && [ [ " ${ PIHOLE_DNS_2 } " ] ] ; then
2017-01-09 07:40:19 +00:00
PIHOLE_DNS_2 = ${ strInvalid }
fi
2017-07-07 00:25:56 +00:00
# If either of the DNS servers are invalid,
2017-07-26 17:00:08 +00:00
if [ [ " ${ PIHOLE_DNS_1 } " = = " ${ strInvalid } " ] ] || [ [ " ${ PIHOLE_DNS_2 } " = = " ${ strInvalid } " ] ] ; then
2017-07-07 00:25:56 +00:00
# explain this to the user
2017-07-26 17:00:08 +00:00
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 }
2017-07-07 00:25:56 +00:00
# and set the variables back to nothing
2017-07-26 17:00:08 +00:00
if [ [ " ${ PIHOLE_DNS_1 } " = = " ${ strInvalid } " ] ] ; then
2017-01-09 07:40:19 +00:00
PIHOLE_DNS_1 = ""
2017-01-09 02:46:15 +00:00
fi
2017-07-26 17:00:08 +00:00
if [ [ " ${ PIHOLE_DNS_2 } " = = " ${ strInvalid } " ] ] ; then
2017-01-09 07:40:19 +00:00
PIHOLE_DNS_2 = ""
2016-12-21 01:22:57 +00:00
fi
2017-07-07 00:25:56 +00:00
# Since the settings will not work, stay in the loop
2017-01-09 07:40:19 +00:00
DNSSettingsCorrect = False
2017-12-11 04:51:54 +00:00
# Otherwise,
2017-01-09 07:40:19 +00:00
else
2017-07-07 00:25:56 +00:00
# Show the settings
2017-07-26 17:00:08 +00:00
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
2017-12-11 04:51:54 +00:00
# and break from the loop since the servers are valid
2017-01-09 07:40:19 +00:00
DNSSettingsCorrect = True
2017-07-07 00:25:56 +00:00
# Otherwise,
2017-01-09 07:40:19 +00:00
else
2017-07-07 00:25:56 +00:00
# If the settings are wrong, the loop continues
2017-01-09 07:40:19 +00:00
DNSSettingsCorrect = False
2016-12-21 01:22:57 +00:00
fi
2017-01-09 07:40:19 +00:00
fi
done
; ;
esac
2016-01-25 05:11:00 +00:00
}
2017-07-07 00:25:56 +00:00
# Allow the user to enable/disable logging
2016-10-31 21:38:48 +00:00
setLogging( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2016-10-31 23:48:58 +00:00
local LogToggleCommand
local LogChooseOptions
local LogChoices
2017-07-07 00:25:56 +00:00
# Ask if the user wants to log queries
2017-07-26 17:00:08 +00:00
LogToggleCommand = ( whiptail --separate-output --radiolist "Do you want to log queries?\\n (Disabling will render graphs on the Admin page useless):" ${ r } ${ c } 6)
2017-07-07 00:25:56 +00:00
# The default selection is on
2016-12-31 16:25:48 +00:00
LogChooseOptions = ( "On (Recommended)" "" on
2016-12-21 01:22:57 +00:00
Off "" off)
2017-07-07 00:25:56 +00:00
# Get the user's choice
2017-06-21 11:49:05 +00:00
LogChoices = $( " ${ LogToggleCommand [@] } " " ${ LogChooseOptions [@] } " 2>& 1 >/dev/tty) || ( echo -e " ${ COL_LIGHT_RED } Cancel was selected, exiting installer ${ COL_NC } " && exit 1)
2016-12-21 01:22:57 +00:00
case ${ LogChoices } in
2017-07-07 00:25:56 +00:00
# If it's on
2016-12-21 01:22:57 +00:00
"On (Recommended)" )
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } Logging On. "
2017-07-07 00:25:56 +00:00
# Set the GLOBAL variable to true so we know what they selected
2016-12-21 01:22:57 +00:00
QUERY_LOGGING = true
; ;
2017-12-11 04:51:54 +00:00
# Otherwise, it's off,
2016-12-21 01:22:57 +00:00
Off)
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } Logging Off. "
2017-07-07 00:25:56 +00:00
# So set it to false
2016-12-21 01:22:57 +00:00
QUERY_LOGGING = false
; ;
esac
2016-10-31 21:38:48 +00:00
}
2018-02-07 05:45:23 +00:00
# Function to ask the user if they want to install the dashboard
2017-01-28 14:38:54 +00:00
setAdminFlag( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2017-01-28 14:38:54 +00:00
local WebToggleCommand
local WebChooseOptions
local WebChoices
2017-07-07 00:25:56 +00:00
# Similar to the logging function, ask what the user wants
2017-01-28 14:38:54 +00:00
WebToggleCommand = ( whiptail --separate-output --radiolist "Do you wish to install the web admin interface?" ${ r } ${ c } 6)
2017-07-07 00:25:56 +00:00
# with the default being enabled
2017-01-28 14:38:54 +00:00
WebChooseOptions = ( "On (Recommended)" "" on
Off "" off)
2017-06-21 11:49:05 +00:00
WebChoices = $( " ${ WebToggleCommand [@] } " " ${ WebChooseOptions [@] } " 2>& 1 >/dev/tty) || ( echo -e " ${ COL_LIGHT_RED } Cancel was selected, exiting installer ${ COL_NC } " && exit 1)
2017-07-07 00:25:56 +00:00
# Depending on their choice
2017-01-28 14:38:54 +00:00
case ${ WebChoices } in
"On (Recommended)" )
2017-07-26 17:00:08 +00:00
echo -e " ${ INFO } Web Interface On "
2017-07-07 00:25:56 +00:00
# Set it to true
2018-04-15 01:08:16 +00:00
INSTALL_WEB_INTERFACE = true
2017-01-28 14:38:54 +00:00
; ;
Off)
2017-07-26 17:00:08 +00:00
echo -e " ${ INFO } Web Interface Off "
2017-07-07 00:25:56 +00:00
# or false
2018-04-15 01:08:16 +00:00
INSTALL_WEB_INTERFACE = false
2017-01-28 14:38:54 +00:00
; ;
esac
2018-04-18 03:11:32 +00:00
# Request user to install web server, if --disable-install-webserver has not been used (INSTALL_WEB_SERVER=true is default).
if [ [ " ${ INSTALL_WEB_SERVER } " = = true ] ] ; then
2018-04-18 03:38:07 +00:00
WebToggleCommand = ( whiptail --separate-output --radiolist "Do you wish to install the web server (lighttpd)?\\n\\nNB: If you disable this, and, do not have an existing webserver installed, the web interface will not function." " ${ r } " " ${ c } " 6)
2018-04-18 03:11:32 +00:00
# with the default being enabled
WebChooseOptions = ( "On (Recommended)" "" on
Off "" off)
WebChoices = $( " ${ WebToggleCommand [@] } " " ${ WebChooseOptions [@] } " 2>& 1 >/dev/tty) || ( echo -e " ${ COL_LIGHT_RED } Cancel was selected, exiting installer ${ COL_NC } " && exit 1)
2018-04-21 07:27:31 +00:00
# Depending on their choice
case ${ WebChoices } in
"On (Recommended)" )
echo -e " ${ INFO } Web Server On "
# set it to true, as clearly seen below.
2018-04-21 07:29:21 +00:00
INSTALL_WEB_SERVER = true
2018-04-21 07:27:31 +00:00
; ;
Off)
echo -e " ${ INFO } Web Server Off "
# or false
2018-04-21 07:29:21 +00:00
INSTALL_WEB_SERVER = false
2017-01-28 14:38:54 +00:00
; ;
esac
2018-04-21 07:27:31 +00:00
fi
2017-01-28 14:38:54 +00:00
}
2018-04-17 08:50:25 +00:00
# A function to display a list of example blocklists for users to select
2018-04-17 18:35:46 +00:00
chooseBlocklists( ) {
2018-04-17 18:46:36 +00:00
# Back up any existing adlist file, on the off chance that it exists. Useful in case of a reconfigure.
if [ [ -f " ${ adlistFile } " ] ] ; then
mv " ${ adlistFile } " " ${ adlistFile } .old "
fi
2018-04-17 08:50:25 +00:00
# Let user select (or not) blocklists via a checklist
2018-04-17 15:22:10 +00:00
cmd = ( whiptail --separate-output --checklist "Pi-hole relies on third party lists in order to block ads.\\n\\nYou can use the suggestions below, and/or add your own after installation\\n\\nTo deselect any list, use the arrow keys and spacebar" " ${ r } " " ${ c } " 7)
2018-04-17 18:35:46 +00:00
# In an array, show the options available (all off by default):
2018-04-17 15:22:10 +00:00
options = ( StevenBlack "StevenBlack's Unified Hosts List" on
MalwareDom "MalwareDomains" on
Cameleon "Cameleon" on
ZeusTracker "ZeusTracker" on
DisconTrack "Disconnect.me Tracking" on
DisconAd "Disconnect.me Ads" on
HostsFile "Hosts-file.net Ads" on)
2018-04-17 08:50:25 +00:00
# In a variable, show the choices available; exit if Cancel is selected
2018-04-17 18:35:46 +00:00
choices = $( " ${ cmd [@] } " " ${ options [@] } " 2>& 1 >/dev/tty) || { echo -e " ${ COL_LIGHT_RED } Cancel was selected, exiting installer ${ COL_NC } " ; rm " ${ adlistFile } " ; exit 1; }
2018-04-17 08:50:25 +00:00
# For each choice available,
for choice in ${ choices }
do
# Set the values to true
case ${ choice } in
StevenBlack ) echo "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" >> " ${ adlistFile } " ; ;
MalwareDom ) echo "https://mirror1.malwaredomains.com/files/justdomains" >> " ${ adlistFile } " ; ;
Cameleon ) echo "http://sysctl.org/cameleon/hosts" >> " ${ adlistFile } " ; ;
ZeusTracker ) echo "https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist" >> " ${ adlistFile } " ; ;
DisconTrack ) echo "https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt" >> " ${ adlistFile } " ; ;
DisconAd ) echo "https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt" >> " ${ adlistFile } " ; ;
HostsFile ) echo "https://hosts-file.net/ad_servers.txt" >> " ${ adlistFile } " ; ;
esac
2018-04-17 15:22:10 +00:00
done
2018-04-17 08:50:25 +00:00
}
2018-02-07 05:45:23 +00:00
# Check if /etc/dnsmasq.conf is from pi-hole. If so replace with an original and install new in .d directory
2016-10-20 02:47:45 +00:00
version_check_dnsmasq( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2016-12-21 01:22:57 +00:00
local dnsmasq_conf = "/etc/dnsmasq.conf"
local dnsmasq_conf_orig = "/etc/dnsmasq.conf.orig"
local dnsmasq_pihole_id_string = "addn-hosts=/etc/pihole/gravity.list"
2017-03-14 00:24:04 +00:00
local dnsmasq_original_config = " ${ PI_HOLE_LOCAL_REPO } /advanced/dnsmasq.conf.original "
local dnsmasq_pihole_01_snippet = " ${ PI_HOLE_LOCAL_REPO } /advanced/01-pihole.conf "
2016-12-21 01:22:57 +00:00
local dnsmasq_pihole_01_location = "/etc/dnsmasq.d/01-pihole.conf"
2017-07-07 00:25:56 +00:00
# If the dnsmasq config file exists
2017-07-26 17:00:08 +00:00
if [ [ -f " ${ dnsmasq_conf } " ] ] ; then
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } Existing dnsmasq.conf found... "
2017-07-07 00:25:56 +00:00
# If gravity.list is found within this file, we presume it's from older versions on Pi-hole,
2016-12-21 01:22:57 +00:00
if grep -q ${ dnsmasq_pihole_id_string } ${ dnsmasq_conf } ; then
2017-04-03 15:29:57 +00:00
echo " it is from a previous Pi-hole install."
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } Backing up dnsmasq.conf to dnsmasq.conf.orig... "
2017-07-07 00:25:56 +00:00
# so backup the original file
2016-12-21 01:22:57 +00:00
mv -f ${ dnsmasq_conf } ${ dnsmasq_conf_orig }
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Backing up dnsmasq.conf to dnsmasq.conf.orig... "
echo -ne " ${ INFO } Restoring default dnsmasq.conf... "
2017-07-07 00:25:56 +00:00
# and replace it with the default
2016-12-21 01:22:57 +00:00
cp ${ dnsmasq_original_config } ${ dnsmasq_conf }
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Restoring default dnsmasq.conf... "
2017-07-07 00:25:56 +00:00
# Otherwise,
2016-12-21 01:22:57 +00:00
else
2017-07-07 00:25:56 +00:00
# Don't to anything
2017-04-03 15:29:57 +00:00
echo " it is not a Pi-hole file, leaving alone!"
2016-12-21 01:22:57 +00:00
fi
else
2017-07-07 00:25:56 +00:00
# If a file cannot be found,
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } No dnsmasq.conf found... restoring default dnsmasq.conf... "
2017-07-07 00:25:56 +00:00
# restore the default one
2016-12-21 01:22:57 +00:00
cp ${ dnsmasq_original_config } ${ dnsmasq_conf }
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } No dnsmasq.conf found... restoring default dnsmasq.conf... "
2016-12-21 01:22:57 +00:00
fi
2017-06-21 11:49:05 +00:00
echo -en " ${ INFO } Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf... "
2018-03-06 18:44:57 +00:00
# Check to see if dnsmasq directory exists (it may not due to being a fresh install and dnsmasq no longer being a dependency)
if [ [ ! -d "/etc/dnsmasq.d" ] ] ; then
mkdir "/etc/dnsmasq.d"
fi
2017-07-07 00:25:56 +00:00
# Copy the new Pi-hole DNS config file into the dnsmasq.d directory
2016-12-21 01:22:57 +00:00
cp ${ dnsmasq_pihole_01_snippet } ${ dnsmasq_pihole_01_location }
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf "
2017-07-07 00:25:56 +00:00
# Replace our placeholder values with the GLOBAL DNS variables that we populated earlier
# First, swap in the interface to listen on
2017-03-03 22:14:12 +00:00
sed -i " s/@INT@/ $PIHOLE_INTERFACE / " ${ dnsmasq_pihole_01_location }
2016-12-21 01:22:57 +00:00
if [ [ " ${ PIHOLE_DNS_1 } " != "" ] ] ; then
2017-07-07 00:25:56 +00:00
# Then swap in the primary DNS server
2016-12-21 01:22:57 +00:00
sed -i " s/@DNS1@/ $PIHOLE_DNS_1 / " ${ dnsmasq_pihole_01_location }
else
2017-07-07 00:25:56 +00:00
#
2016-12-21 01:22:57 +00:00
sed -i '/^server=@DNS1@/d' ${ dnsmasq_pihole_01_location }
fi
if [ [ " ${ PIHOLE_DNS_2 } " != "" ] ] ; then
2017-07-07 00:25:56 +00:00
# Then swap in the primary DNS server
2016-12-21 01:22:57 +00:00
sed -i " s/@DNS2@/ $PIHOLE_DNS_2 / " ${ dnsmasq_pihole_01_location }
else
2017-07-07 00:25:56 +00:00
#
2016-12-21 01:22:57 +00:00
sed -i '/^server=@DNS2@/d' ${ dnsmasq_pihole_01_location }
fi
2017-07-07 00:25:56 +00:00
#
2016-12-21 01:22:57 +00:00
sed -i 's/^#conf-dir=\/etc\/dnsmasq.d$/conf-dir=\/etc\/dnsmasq.d/' ${ dnsmasq_conf }
2017-07-07 00:25:56 +00:00
# If the user does not want to enable logging,
2016-12-21 01:22:57 +00:00
if [ [ " ${ QUERY_LOGGING } " = = false ] ] ; then
2017-07-07 00:25:56 +00:00
# Disable it by commenting out the directive in the DNS config file
2016-10-31 21:38:48 +00:00
sed -i 's/^log-queries/#log-queries/' ${ dnsmasq_pihole_01_location }
2017-07-07 00:25:56 +00:00
# Otherwise,
2016-10-31 21:38:48 +00:00
else
2017-07-07 00:25:56 +00:00
# enable it by uncommenting the directive in the DNS config file
2016-10-31 21:38:48 +00:00
sed -i 's/^#log-queries/log-queries/' ${ dnsmasq_pihole_01_location }
fi
2016-01-25 05:04:02 +00:00
}
2017-07-10 19:12:30 +00:00
# Clean an existing installation to prepare for upgrade/reinstall
2016-11-02 07:14:25 +00:00
clean_existing( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
# ${1} Directory to clean
2016-11-02 07:14:25 +00:00
local clean_directory = " ${ 1 } "
2017-07-07 00:25:56 +00:00
# Make ${2} the new one?
2017-01-15 04:16:27 +00:00
shift
2017-07-07 00:25:56 +00:00
# ${2} Array of files to remove
2017-01-15 04:16:27 +00:00
local old_files = ( " $@ " )
2016-11-02 07:14:25 +00:00
2017-07-07 00:25:56 +00:00
# For each script found in the old files array
2016-12-21 01:22:57 +00:00
for script in " ${ old_files [@] } " ; do
2017-07-07 00:25:56 +00:00
# Remove them
2017-01-15 04:16:27 +00:00
rm -f " ${ clean_directory } / ${ script } .sh "
2016-12-21 01:22:57 +00:00
done
2016-11-02 07:14:25 +00:00
}
2016-10-05 16:57:48 +00:00
2017-07-07 00:25:56 +00:00
# Install the scripts from repository to their various locations
2016-11-02 07:14:25 +00:00
installScripts( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2017-06-21 11:49:05 +00:00
local str = " Installing scripts from ${ PI_HOLE_LOCAL_REPO } "
echo -ne " ${ INFO } ${ str } ... "
2016-11-02 07:14:25 +00:00
2016-12-21 01:22:57 +00:00
# Clear out script files from Pi-hole scripts directory.
2017-01-15 04:16:27 +00:00
clean_existing " ${ PI_HOLE_INSTALL_DIR } " " ${ PI_HOLE_FILES [@] } "
2016-11-02 07:14:25 +00:00
# Install files from local core repository
2016-11-02 13:34:57 +00:00
if is_repo " ${ PI_HOLE_LOCAL_REPO } " ; then
2017-07-07 00:25:56 +00:00
# move into the directory
2016-11-02 07:14:25 +00:00
cd " ${ PI_HOLE_LOCAL_REPO } "
2017-07-07 00:25:56 +00:00
# Install the scripts by:
# -o setting the owner to the user
2017-12-11 04:51:54 +00:00
# -Dm755 create all leading components of destination except the last, then copy the source to the destination and setting the permissions to 755
2017-07-07 00:25:56 +00:00
#
# This first one is the directory
2017-01-09 07:01:18 +00:00
install -o " ${ USER } " -Dm755 -d " ${ PI_HOLE_INSTALL_DIR } "
2017-07-07 00:25:56 +00:00
# The rest are the scripts Pi-hole needs
2017-01-09 07:01:18 +00:00
install -o " ${ USER } " -Dm755 -t " ${ PI_HOLE_INSTALL_DIR } " gravity.sh
install -o " ${ USER } " -Dm755 -t " ${ PI_HOLE_INSTALL_DIR } " ./advanced/Scripts/*.sh
install -o " ${ USER } " -Dm755 -t " ${ PI_HOLE_INSTALL_DIR } " ./automated\ install/uninstall.sh
2017-06-21 11:49:05 +00:00
install -o " ${ USER } " -Dm755 -t " ${ PI_HOLE_INSTALL_DIR } " ./advanced/Scripts/COL_TABLE
2016-11-02 07:14:25 +00:00
install -o " ${ USER } " -Dm755 -t /usr/local/bin/ pihole
install -Dm644 ./advanced/bash-completion/pihole /etc/bash_completion.d/pihole
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2017-07-07 00:25:56 +00:00
# Otherwise,
2016-11-02 07:14:25 +00:00
else
2017-07-07 00:25:56 +00:00
# Show an error and exit
2017-07-26 17:00:08 +00:00
echo -e " ${ OVER } ${ CROSS } ${ str }
${ COL_LIGHT_RED } Error: Local repo ${ PI_HOLE_LOCAL_REPO } not found, exiting installer${ COL_NC } "
2016-11-02 07:14:25 +00:00
exit 1
fi
2015-12-03 17:25:13 +00:00
}
2017-07-07 00:25:56 +00:00
# Install the configs from PI_HOLE_LOCAL_REPO to their various locations
2016-01-27 06:11:38 +00:00
installConfigs( ) {
2017-06-21 11:49:05 +00:00
echo ""
echo -e " ${ INFO } Installing configs from ${ PI_HOLE_LOCAL_REPO } ... "
2017-07-07 00:25:56 +00:00
# Make sure Pi-hole's config files are in place
2016-12-21 01:22:57 +00:00
version_check_dnsmasq
2017-02-04 15:25:11 +00:00
2017-07-07 00:25:56 +00:00
# If the user chose to install the dashboard,
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_SERVER } " = = true ] ] ; then
2017-07-07 00:25:56 +00:00
# and if the Web server conf directory does not exist,
2017-07-26 17:00:08 +00:00
if [ [ ! -d "/etc/lighttpd" ] ] ; then
2017-07-07 00:25:56 +00:00
# make it
2017-02-04 15:25:11 +00:00
mkdir /etc/lighttpd
2017-07-07 00:25:56 +00:00
# and set the owners
2017-02-04 15:25:11 +00:00
chown " ${ USER } " :root /etc/lighttpd
2017-07-07 00:25:56 +00:00
# Otherwise, if the config file already exists
2017-07-26 17:00:08 +00:00
elif [ [ -f "/etc/lighttpd/lighttpd.conf" ] ] ; then
2017-07-07 00:25:56 +00:00
# back up the original
2017-02-04 15:25:11 +00:00
mv /etc/lighttpd/lighttpd.conf /etc/lighttpd/lighttpd.conf.orig
fi
2017-07-07 00:25:56 +00:00
# and copy in the config file Pi-hole needs
2017-03-14 00:24:04 +00:00
cp ${ PI_HOLE_LOCAL_REPO } /advanced/${ LIGHTTPD_CFG } /etc/lighttpd/lighttpd.conf
2017-09-09 18:30:53 +00:00
# if there is a custom block page in the html/pihole directory, replace 404 handler in lighttpd config
if [ [ -f "/var/www/html/pihole/custom.php" ] ] ; then
sed -i 's/^\(server\.error-handler-404\s*=\s*\).*$/\1"pihole\/custom\.php"/' /etc/lighttpd/lighttpd.conf
fi
2017-07-07 00:25:56 +00:00
# Make the directories if they do not exist and set the owners
2017-02-04 15:25:11 +00:00
mkdir -p /var/run/lighttpd
chown ${ LIGHTTPD_USER } :${ LIGHTTPD_GROUP } /var/run/lighttpd
mkdir -p /var/cache/lighttpd/compress
chown ${ LIGHTTPD_USER } :${ LIGHTTPD_GROUP } /var/cache/lighttpd/compress
mkdir -p /var/cache/lighttpd/uploads
chown ${ LIGHTTPD_USER } :${ LIGHTTPD_GROUP } /var/cache/lighttpd/uploads
2016-12-21 01:22:57 +00:00
fi
2015-12-03 17:25:13 +00:00
}
2016-10-10 08:25:11 +00:00
stop_service( ) {
2016-12-21 01:22:57 +00:00
# Stop service passed in as argument.
# Can softfail, as process may not be installed when this is called
2018-03-18 00:38:34 +00:00
local str = " Stopping ${ 1 } service "
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } ${ str } ... "
2016-12-27 19:53:23 +00:00
if command -v systemctl & > /dev/null; then
2016-12-21 10:54:52 +00:00
systemctl stop " ${ 1 } " & > /dev/null || true
2016-12-21 01:22:57 +00:00
else
2016-12-21 10:54:52 +00:00
service " ${ 1 } " stop & > /dev/null || true
2016-12-21 01:22:57 +00:00
fi
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } ... "
2016-10-10 13:06:34 +00:00
}
2017-07-07 00:25:56 +00:00
# Start/Restart service passed in as argument
2016-10-10 13:06:34 +00:00
start_service( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2018-03-18 00:38:34 +00:00
local str = " Starting ${ 1 } service "
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# If systemctl exists,
2016-12-27 19:53:23 +00:00
if command -v systemctl & > /dev/null; then
2017-07-07 00:25:56 +00:00
# use that to restart the service
2016-12-21 10:54:52 +00:00
systemctl restart " ${ 1 } " & > /dev/null
2017-07-07 00:25:56 +00:00
# Otherwise,
2016-12-21 01:22:57 +00:00
else
2017-07-07 00:25:56 +00:00
# fall back to the service command
2016-12-21 10:54:52 +00:00
service " ${ 1 } " restart & > /dev/null
2016-12-21 01:22:57 +00:00
fi
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2016-10-10 13:06:34 +00:00
}
2017-07-07 00:25:56 +00:00
# Enable service so that it will start with next reboot
2016-10-10 13:06:34 +00:00
enable_service( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2018-03-18 00:38:34 +00:00
local str = " Enabling ${ 1 } service to start on reboot "
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# If systemctl exists,
2016-12-27 19:53:23 +00:00
if command -v systemctl & > /dev/null; then
2017-07-07 00:25:56 +00:00
# use that to enable the service
2016-12-21 10:54:52 +00:00
systemctl enable " ${ 1 } " & > /dev/null
2018-03-17 22:48:11 +00:00
# Otherwise,
2016-12-21 01:22:57 +00:00
else
2017-07-07 00:25:56 +00:00
# use update-rc.d to accomplish this
2016-12-21 10:54:52 +00:00
update-rc.d " ${ 1 } " defaults & > /dev/null
2016-12-21 01:22:57 +00:00
fi
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2015-12-03 17:25:13 +00:00
}
2016-10-10 05:05:06 +00:00
2018-03-06 18:44:57 +00:00
# Disable service so that it will not with next reboot
disable_service( ) {
# Local, named variables
2018-03-18 00:38:34 +00:00
local str = " Disabling ${ 1 } service "
2018-03-06 18:44:57 +00:00
echo -ne " ${ INFO } ${ str } ... "
# If systemctl exists,
if command -v systemctl & > /dev/null; then
# use that to disable the service
systemctl disable " ${ 1 } " & > /dev/null
2018-03-17 22:48:11 +00:00
# Otherwise,
2018-03-06 18:44:57 +00:00
else
# use update-rc.d to accomplish this
update-rc.d " ${ 1 } " disable & > /dev/null
fi
echo -e " ${ OVER } ${ TICK } ${ str } "
}
2018-03-07 23:31:28 +00:00
check_service_active( ) {
# If systemctl exists,
if command -v systemctl & > /dev/null; then
2018-03-17 22:56:50 +00:00
# use that to check the status of the service
2018-03-18 00:38:34 +00:00
systemctl is-enabled " ${ 1 } " > /dev/null
2018-03-17 22:48:11 +00:00
# Otherwise,
2018-03-07 23:31:28 +00:00
else
# fall back to service command
2018-03-18 00:38:34 +00:00
service " ${ 1 } " status > /dev/null
2018-03-18 00:13:10 +00:00
fi
2018-03-07 23:31:28 +00:00
}
2018-05-15 10:23:36 +00:00
# Systemd-resolved's DNSStubListener and dnsmasq can't share port 53.
disable_resolved_stublistener( ) {
2018-05-16 21:44:07 +00:00
echo -en " ${ INFO } Testing if systemd-resolved is enabled "
2018-05-15 21:11:23 +00:00
# Check if Systemd-resolved's DNSStubListener is enabled and active on port 53
2018-05-15 10:23:36 +00:00
if check_service_active "systemd-resolved" ; then
# Check if DNSStubListener is enabled
2018-05-16 21:44:07 +00:00
echo -en " ${ OVER } ${ INFO } Testing if systemd-resolved DNSStub-Listener is active "
2018-05-15 21:11:23 +00:00
if ( grep -E '#?DNSStubListener=yes' /etc/systemd/resolved.conf & > /dev/null ) ; then
2018-05-15 10:23:36 +00:00
# Disable the DNSStubListener to unbind it from port 53
# Note that this breaks dns functionality on host until dnsmasq/ftl are up and running
2018-05-16 21:44:07 +00:00
echo -en " ${ OVER } ${ TICK } Disabling systemd-resolved DNSStubListener "
2018-05-15 10:23:36 +00:00
# Make a backup of the original /etc/systemd/resolved.conf
# (This will need to be restored on uninstallation)
2018-05-15 21:11:23 +00:00
sed -r -i.orig 's/#?DNSStubListener=yes/DNSStubListener=no/g' /etc/systemd/resolved.conf
2018-05-16 21:44:07 +00:00
echo -e " and restarting systemd-resolved"
2018-05-15 21:28:32 +00:00
systemctl reload-or-restart systemd-resolved
2018-05-16 21:44:07 +00:00
else
echo -e " ${ OVER } ${ INFO } Systemd-resolved does not need to be restarted "
2018-05-15 10:23:36 +00:00
fi
2018-05-16 21:44:07 +00:00
else
echo -e " ${ OVER } ${ INFO } Systemd-resolved is not enabled "
2018-05-15 10:23:36 +00:00
fi
}
2017-01-28 23:44:31 +00:00
update_package_cache( ) {
2017-07-07 00:25:56 +00:00
# Running apt-get update/upgrade with minimal output can cause some issues with
# requiring user input (e.g password for phpmyadmin see #218)
2016-12-21 01:22:57 +00:00
2017-07-07 00:25:56 +00:00
# Update package cache on apt based OSes. Do this every time since
# it's quick and packages can be updated at any time.
2016-12-21 01:22:57 +00:00
2017-07-07 00:25:56 +00:00
# Local, named variables
2017-06-21 11:49:05 +00:00
local str = "Update local cache of available packages"
echo ""
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# Create a command from the package cache variable
2017-03-03 10:35:44 +00:00
if eval " ${ UPDATE_PKG_CACHE } " & > /dev/null; then
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2017-07-07 00:25:56 +00:00
# Otherwise,
2017-01-29 00:33:40 +00:00
else
2017-07-07 00:25:56 +00:00
# show an error and exit
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ CROSS } ${ str } "
echo -ne " ${ COL_LIGHT_RED } Error: Unable to update package cache. Please try \" ${ UPDATE_PKG_CACHE } \" ${ COL_NC } "
2017-03-02 23:54:58 +00:00
return 1
2017-01-28 23:44:31 +00:00
fi
2016-10-10 09:24:03 +00:00
}
2017-07-07 00:25:56 +00:00
# Let user know if they have outdated packages on their system and
# advise them to run a package update at soonest possible.
2016-10-20 02:47:45 +00:00
notify_package_updates_available( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2017-06-21 11:49:05 +00:00
local str = " Checking ${ PKG_MANAGER } for upgraded packages "
2017-07-26 17:00:08 +00:00
echo -ne " \\n ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# Store the list of packages in a variable
2016-12-21 01:22:57 +00:00
updatesToInstall = $( eval " ${ PKG_COUNT } " )
2017-07-26 17:00:08 +00:00
2016-12-29 09:34:49 +00:00
if [ [ -d " /lib/modules/ $( uname -r) " ] ] ; then
2017-07-07 00:25:56 +00:00
#
2017-07-26 17:00:08 +00:00
if [ [ " ${ updatesToInstall } " -eq 0 ] ] ; then
2017-07-07 00:25:56 +00:00
#
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } ... up to date! "
echo ""
2016-12-29 09:34:49 +00:00
else
2017-07-07 00:25:56 +00:00
#
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } ... ${ updatesToInstall } updates available "
echo -e " ${ INFO } ${ COL_LIGHT_GREEN } It is recommended to update your OS after installing the Pi-hole! ${ COL_NC } "
echo ""
2016-12-29 09:34:49 +00:00
fi
2016-12-29 09:35:52 +00:00
else
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ CROSS } ${ str }
2017-07-26 17:00:08 +00:00
Kernel update detected. If the install fails, please reboot and try again\\ n"
2016-12-21 01:22:57 +00:00
fi
2016-10-10 05:00:23 +00:00
}
2017-07-07 00:25:56 +00:00
# What's this doing outside of a function in the middle of nowhere?
2017-06-21 11:49:05 +00:00
counter = 0
2017-07-07 00:25:56 +00:00
2016-10-20 02:47:45 +00:00
install_dependent_packages( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables should be used here, especially for an iterator
# Add one to the counter
2017-06-21 11:49:05 +00:00
counter = $(( counter+1))
2017-07-07 00:25:56 +00:00
# If it equals 1,
2017-07-26 17:00:08 +00:00
if [ [ " ${ counter } " = = 1 ] ] ; then
2017-07-07 00:25:56 +00:00
#
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } Installer Dependency checks... "
else
2017-07-07 00:25:56 +00:00
#
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } Main Dependency checks... "
fi
2016-12-21 01:22:57 +00:00
# Install packages passed in via argument array
# No spinner - conflicts with set -e
declare -a argArray1 = ( " ${ !1 } " )
2016-12-22 06:20:23 +00:00
declare -a installArray
2016-12-21 01:22:57 +00:00
2016-12-22 06:20:23 +00:00
# Debian based package install - debconf will download the entire package list
# so we just create an array of packages not currently installed to cut down on the
# amount of download traffic.
# NOTE: We may be able to use this installArray in the future to create a list of package that were
# installed by us, and remove only the installed packages, and not the entire list.
2016-12-21 00:47:43 +00:00
if command -v debconf-apt-progress & > /dev/null; then
2017-07-07 00:25:56 +00:00
# For each package,
2016-12-21 00:47:43 +00:00
for i in " ${ argArray1 [@] } " ; do
2017-08-23 01:51:16 +00:00
echo -ne " ${ INFO } Checking for $i ... "
2017-07-07 00:25:56 +00:00
#
2016-12-22 06:57:42 +00:00
if dpkg-query -W -f= '${Status}' " ${ i } " 2>/dev/null | grep "ok installed" & > /dev/null; then
2017-07-07 00:25:56 +00:00
#
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Checking for $i "
2016-12-22 06:20:23 +00:00
else
2017-07-07 00:25:56 +00:00
#
2017-12-11 17:45:30 +00:00
echo -e " ${ OVER } ${ INFO } Checking for $i (will be installed) "
2017-07-07 00:25:56 +00:00
#
2016-12-22 06:20:23 +00:00
installArray += ( " ${ i } " )
fi
2016-12-21 00:47:43 +00:00
done
2017-07-07 00:25:56 +00:00
#
2017-07-26 17:00:08 +00:00
if [ [ " ${# installArray [@] } " -gt 0 ] ] ; then
2017-07-07 00:25:56 +00:00
#
2017-03-03 10:52:49 +00:00
test_dpkg_lock
2017-07-07 00:25:56 +00:00
#
2017-01-09 07:01:18 +00:00
debconf-apt-progress -- " ${ PKG_INSTALL [@] } " " ${ installArray [@] } "
2016-12-25 00:52:46 +00:00
return
fi
2017-06-21 11:49:05 +00:00
echo ""
2017-07-07 00:25:56 +00:00
#
2016-12-22 07:38:31 +00:00
return 0
2016-12-21 00:47:43 +00:00
fi
2016-12-22 07:38:31 +00:00
2017-07-07 00:25:56 +00:00
# Install Fedora/CentOS packages
2016-12-22 07:38:31 +00:00
for i in " ${ argArray1 [@] } " ; do
2017-08-23 01:51:16 +00:00
echo -ne " ${ INFO } Checking for $i ... "
2017-07-07 00:25:56 +00:00
#
2016-12-22 11:21:37 +00:00
if ${ PKG_MANAGER } -q list installed " ${ i } " & > /dev/null; then
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Checking for $i "
2016-12-22 07:38:31 +00:00
else
2017-12-11 17:45:30 +00:00
echo -e " ${ OVER } ${ INFO } Checking for $i (will be installed) "
2017-07-07 00:25:56 +00:00
#
2016-12-22 07:38:31 +00:00
installArray += ( " ${ i } " )
fi
done
2017-11-05 10:02:04 +00:00
#
if [ [ " ${# installArray [@] } " -gt 0 ] ] ; then
2017-07-07 00:25:56 +00:00
#
2017-11-05 10:02:04 +00:00
" ${ PKG_INSTALL [@] } " " ${ installArray [@] } " & > /dev/null
return
fi
echo ""
return 0
2015-12-03 17:25:13 +00:00
}
2017-07-07 00:25:56 +00:00
# Install the Web interface dashboard
2016-01-27 06:11:38 +00:00
installPiholeWeb( ) {
2017-06-21 11:49:05 +00:00
echo ""
echo " ${ INFO } Installing blocking page... "
2016-12-21 01:22:57 +00:00
2017-09-09 18:07:48 +00:00
local str = "Creating directory for blocking page, and copying files"
echo -ne " ${ INFO } ${ str } ... "
# Install the directory
install -d /var/www/html/pihole
# and the blockpage
install -D ${ PI_HOLE_LOCAL_REPO } /advanced/{ index,blockingpage} .* /var/www/html/pihole/
2017-10-03 14:13:02 +00:00
# Remove superseded file
if [ [ -e "/var/www/html/pihole/index.js" ] ] ; then
rm "/var/www/html/pihole/index.js"
fi
2017-09-09 18:07:48 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2016-12-21 01:22:57 +00:00
2017-09-09 18:07:48 +00:00
local str = "Backing up index.lighttpd.html"
echo -ne " ${ INFO } ${ str } ... "
# If the default index file exists,
if [ [ -f "/var/www/html/index.lighttpd.html" ] ] ; then
# back it up
mv /var/www/html/index.lighttpd.html /var/www/html/index.lighttpd.orig
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2018-03-17 22:48:11 +00:00
# Otherwise,
2017-09-09 18:07:48 +00:00
else
# don't do anything
echo -e " ${ OVER } ${ CROSS } ${ str }
2017-12-06 15:17:31 +00:00
No default index.lighttpd.html file found... not backing up"
2016-12-21 01:22:57 +00:00
fi
2017-01-28 05:50:32 +00:00
2017-07-07 00:25:56 +00:00
# Install Sudoers file
2017-06-21 11:49:05 +00:00
echo ""
local str = "Installing sudoer file"
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# Make the .d directory if it doesn't exist
2016-12-21 01:22:57 +00:00
mkdir -p /etc/sudoers.d/
2017-07-07 00:25:56 +00:00
# and copy in the pihole sudoers file
2017-03-14 00:24:04 +00:00
cp ${ PI_HOLE_LOCAL_REPO } /advanced/pihole.sudo /etc/sudoers.d/pihole
2016-12-22 12:26:11 +00:00
# Add lighttpd user (OS dependent) to sudoers file
echo " ${ LIGHTTPD_USER } ALL=NOPASSWD: /usr/local/bin/pihole " >> /etc/sudoers.d/pihole
2016-12-23 15:57:51 +00:00
2017-07-07 00:25:56 +00:00
# If the Web server user is lighttpd,
2016-12-23 16:12:38 +00:00
if [ [ " $LIGHTTPD_USER " = = "lighttpd" ] ] ; then
2016-12-23 15:57:51 +00:00
# Allow executing pihole via sudo with Fedora
2017-12-11 04:51:54 +00:00
# Usually /usr/local/bin is not permitted as directory for sudoable programs
2016-12-23 15:57:51 +00:00
echo "Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin" >> /etc/sudoers.d/pihole
fi
2017-07-07 00:25:56 +00:00
# Set the strict permissions on the file
2016-12-21 01:22:57 +00:00
chmod 0440 /etc/sudoers.d/pihole
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2015-12-03 17:25:13 +00:00
}
2017-07-07 00:25:56 +00:00
# Installs a cron file
2016-01-27 06:11:38 +00:00
installCron( ) {
2016-12-21 01:22:57 +00:00
# Install the cron job
2017-06-21 11:49:05 +00:00
local str = "Installing latest Cron script"
echo ""
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# Copy the cron file over from the local repo
2017-03-14 00:24:04 +00:00
cp ${ PI_HOLE_LOCAL_REPO } /advanced/pihole.cron /etc/cron.d/pihole
2017-10-21 13:52:53 +00:00
# Randomize gravity update time
2017-12-21 11:42:47 +00:00
sed -i " s/59 1 / $(( 1 + RANDOM % 58 )) $(( 3 + RANDOM % 2 )) / " /etc/cron.d/pihole
# Randomize update checker time
sed -i " s/59 17/ $(( 1 + RANDOM % 58 )) $(( 12 + RANDOM % 8 )) / " /etc/cron.d/pihole
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2015-12-03 17:25:13 +00:00
}
2017-07-07 00:25:56 +00:00
# Gravity is a very important script as it aggregates all of the domains into a single HOSTS formatted list,
# which is what Pi-hole needs to begin blocking ads
2016-01-27 06:11:38 +00:00
runGravity( ) {
2017-07-07 00:25:56 +00:00
# Run gravity in the current shell
2018-02-22 14:45:31 +00:00
{ /opt/pihole/gravity.sh --force; }
2016-01-19 22:52:29 +00:00
}
2017-07-07 00:25:56 +00:00
# Check if the pihole user exists and create if it does not
2016-10-20 02:47:45 +00:00
create_pihole_user( ) {
2017-06-21 11:49:05 +00:00
local str = "Checking for user 'pihole'"
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# If the user pihole exists,
2017-01-15 01:01:47 +00:00
if id -u pihole & > /dev/null; then
2017-07-07 00:25:56 +00:00
# just show a success
2017-06-21 11:49:05 +00:00
echo -ne " ${ OVER } ${ TICK } ${ str } "
2018-03-17 22:48:11 +00:00
# Otherwise,
2017-01-15 01:01:47 +00:00
else
2017-06-21 11:49:05 +00:00
echo -ne " ${ OVER } ${ CROSS } ${ str } "
local str = "Creating user 'pihole'"
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# create her with the useradd command
2017-01-15 01:01:47 +00:00
useradd -r -s /usr/sbin/nologin pihole
2017-06-21 11:49:05 +00:00
echo -ne " ${ OVER } ${ TICK } ${ str } "
2017-01-15 01:01:47 +00:00
fi
2016-01-25 05:28:53 +00:00
}
2016-01-20 23:34:18 +00:00
2017-07-07 00:25:56 +00:00
# Allow HTTP and DNS traffic
2016-05-14 23:05:40 +00:00
configureFirewall( ) {
2017-06-21 11:49:05 +00:00
echo ""
2017-07-07 00:25:56 +00:00
# If a firewall is running,
2017-01-24 23:44:48 +00:00
if firewall-cmd --state & > /dev/null; then
2017-12-11 04:51:54 +00:00
# ask if the user wants to install Pi-hole's default firewall rules
2017-07-26 17:00:08 +00:00
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 } || \
2017-06-21 11:49:05 +00:00
{ echo -e " ${ INFO } Not installing firewall rulesets. " ; return 0; }
2018-03-06 18:44:57 +00:00
echo -e " ${ TICK } Configuring FirewallD for httpd and pihole-FTL "
2017-12-11 04:51:54 +00:00
# Allow HTTP and DNS traffic
2017-03-15 22:29:33 +00:00
firewall-cmd --permanent --add-service= http --add-service= dns
2017-07-07 00:25:56 +00:00
# Reload the firewall to apply these changes
2016-12-29 23:57:29 +00:00
firewall-cmd --reload
2017-01-17 21:56:34 +00:00
return 0
2017-01-01 03:07:40 +00:00
# Check for proper kernel modules to prevent failure
2017-01-13 17:12:03 +00:00
elif modinfo ip_tables & > /dev/null && command -v iptables & > /dev/null; then
2017-01-01 03:07:40 +00:00
# If chain Policy is not ACCEPT or last Rule is not ACCEPT
# then check and insert our Rules above the DROP/REJECT Rule.
2017-01-01 22:38:10 +00:00
if iptables -S INPUT | head -n1 | grep -qv '^-P.*ACCEPT$' || iptables -S INPUT | tail -n1 | grep -qv '^-\(A\|P\).*ACCEPT$' ; then
2017-07-26 17:00:08 +00:00
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 } || \
2017-06-21 11:49:05 +00:00
{ echo -e " ${ INFO } Not installing firewall rulesets. " ; return 0; }
2017-07-26 17:00:08 +00:00
echo -e " ${ TICK } Installing new IPTables firewall rulesets "
2017-01-01 03:07:40 +00:00
# Check chain first, otherwise a new rule will duplicate old ones
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
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
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
2017-05-20 13:47:51 +00:00
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
2017-01-17 21:56:34 +00:00
return 0
2017-01-01 03:07:40 +00:00
fi
2018-03-17 22:48:11 +00:00
# Otherwise,
2016-12-21 01:22:57 +00:00
else
2017-07-07 00:25:56 +00:00
# no firewall is running
2017-07-26 17:00:08 +00:00
echo -e " ${ INFO } No active firewall detected.. skipping firewall configuration "
2017-07-07 00:25:56 +00:00
# so just exit
2017-01-17 21:56:34 +00:00
return 0
2016-12-21 01:22:57 +00:00
fi
2017-07-26 17:00:08 +00:00
echo -e " ${ INFO } Skipping firewall configuration "
2016-05-14 23:05:40 +00:00
}
2017-07-07 00:25:56 +00:00
#
2016-08-26 21:45:38 +00:00
finalExports( ) {
2017-07-07 00:25:56 +00:00
# If the Web interface is not set to be installed,
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_INTERFACE } " = = false ] ] ; then
2017-07-07 00:25:56 +00:00
# and if there is not an IPv4 address,
2017-07-26 17:00:08 +00:00
if [ [ " ${ IPV4_ADDRESS } " ] ] ; then
2017-07-07 00:25:56 +00:00
# there is no block page, so set IPv4 to 0.0.0.0 (all IP addresses)
2017-02-04 15:25:11 +00:00
IPV4_ADDRESS = "0.0.0.0"
fi
2017-07-26 17:00:08 +00:00
if [ [ " ${ IPV6_ADDRESS } " ] ] ; then
2017-07-07 00:25:56 +00:00
# and IPv6 to ::/0
2017-02-04 15:25:11 +00:00
IPV6_ADDRESS = "::/0"
fi
fi
2017-07-07 00:25:56 +00:00
# If the setup variable file exists,
2017-07-26 17:00:08 +00:00
if [ [ -e " ${ setupVars } " ] ] ; then
# update the variables in the file
2018-04-23 10:59:39 +00:00
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_SERVER/d;/INSTALL_WEB_INTERFACE/d;/LIGHTTPD_ENABLED/d;' " ${ setupVars } "
2016-12-21 01:22:57 +00:00
fi
2017-07-07 00:25:56 +00:00
# echo the information to the user
2016-10-10 09:57:04 +00:00
{
2016-12-21 01:22:57 +00:00
echo " PIHOLE_INTERFACE= ${ PIHOLE_INTERFACE } "
echo " IPV4_ADDRESS= ${ IPV4_ADDRESS } "
echo " IPV6_ADDRESS= ${ IPV6_ADDRESS } "
echo " PIHOLE_DNS_1= ${ PIHOLE_DNS_1 } "
echo " PIHOLE_DNS_2= ${ PIHOLE_DNS_2 } "
echo " QUERY_LOGGING= ${ QUERY_LOGGING } "
2018-04-15 01:08:16 +00:00
echo " INSTALL_WEB_SERVER= ${ INSTALL_WEB_SERVER } "
echo " INSTALL_WEB_INTERFACE= ${ INSTALL_WEB_INTERFACE } "
2017-07-16 15:44:14 +00:00
echo " LIGHTTPD_ENABLED= ${ LIGHTTPD_ENABLED } "
2016-10-10 12:45:37 +00:00
} >> " ${ setupVars } "
2016-12-28 16:31:55 +00:00
2017-07-26 13:34:40 +00:00
# Bring in the current settings and the functions to manipulate them
2016-12-28 16:31:55 +00:00
source " ${ setupVars } "
2017-03-14 00:24:04 +00:00
source " ${ PI_HOLE_LOCAL_REPO } /advanced/Scripts/webpage.sh "
2017-01-02 09:50:59 +00:00
2017-07-26 13:34:40 +00:00
# Look for DNS server settings which would have to be reapplied
2017-07-26 16:15:23 +00:00
ProcessDNSSettings
2017-01-02 09:50:59 +00:00
2017-07-26 16:15:23 +00:00
# Look for DHCP server settings which would have to be reapplied
ProcessDHCPSettings
2015-11-07 18:07:50 +00:00
}
2017-07-07 00:25:56 +00:00
# Install the logrotate script
2017-01-27 13:16:24 +00:00
installLogrotate( ) {
2017-07-07 00:25:56 +00:00
2017-06-21 11:49:05 +00:00
local str = "Installing latest logrotate script"
echo ""
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# Copy the file over from the local repo
2017-03-14 00:24:04 +00:00
cp ${ PI_HOLE_LOCAL_REPO } /advanced/logrotate /etc/pihole/logrotate
2017-01-27 13:28:59 +00:00
# Different operating systems have different user / group
# settings for logrotate that makes it impossible to create
# a static logrotate file that will work with e.g.
# Rasbian and Ubuntu at the same time. Hence, we have to
# customize the logrotate script here in order to reflect
# the local properties of the /var/log directory
logusergroup = " $( stat -c '%U %G' /var/log) "
2017-07-07 00:25:56 +00:00
# If the variable has a value,
2017-07-26 17:00:08 +00:00
if [ [ ! -z " ${ logusergroup } " ] ] ; then
2017-07-07 00:25:56 +00:00
#
2017-06-03 12:51:35 +00:00
sed -i " s/# su #/su ${ logusergroup } /g; " /etc/pihole/logrotate
2017-01-27 13:28:59 +00:00
fi
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2017-01-27 13:16:24 +00:00
}
2017-12-11 04:51:54 +00:00
# At some point in the future this list can be pruned, for now we'll need it to ensure updates don't break.
# Refactoring of install script has changed the name of a couple of variables. Sort them out here.
accountForRefactor( ) {
sed -i 's/piholeInterface/PIHOLE_INTERFACE/g' ${ setupVars }
sed -i 's/IPv4_address/IPV4_ADDRESS/g' ${ setupVars }
sed -i 's/IPv4addr/IPV4_ADDRESS/g' ${ setupVars }
sed -i 's/IPv6_address/IPV6_ADDRESS/g' ${ setupVars }
sed -i 's/piholeIPv6/IPV6_ADDRESS/g' ${ setupVars }
sed -i 's/piholeDNS1/PIHOLE_DNS_1/g' ${ setupVars }
sed -i 's/piholeDNS2/PIHOLE_DNS_2/g' ${ setupVars }
sed -i 's/^INSTALL_WEB=/INSTALL_WEB_INTERFACE=/' ${ setupVars }
# Add 'INSTALL_WEB_SERVER', if its not been applied already: https://github.com/pi-hole/pi-hole/pull/2115
if ! grep -q '^INSTALL_WEB_SERVER=' ${ setupVars } ; then
local webserver_installed = false
if grep -q '^INSTALL_WEB_INTERFACE=true' ${ setupVars } ; then
webserver_installed = true
fi
echo -e " INSTALL_WEB_SERVER= $webserver_installed " >> ${ setupVars }
fi
}
2017-07-07 00:25:56 +00:00
# Install base files and web interface
2016-08-19 21:45:24 +00:00
installPihole( ) {
2017-07-07 00:25:56 +00:00
# Create the pihole user
2016-12-21 01:22:57 +00:00
create_pihole_user
2017-01-28 15:45:14 +00:00
2017-07-07 00:25:56 +00:00
# If the user wants to install the Web interface,
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_INTERFACE } " = = true ] ] ; then
2017-07-26 17:00:08 +00:00
if [ [ ! -d "/var/www/html" ] ] ; then
2017-07-07 00:25:56 +00:00
# make the Web directory if necessary
2017-01-28 15:45:14 +00:00
mkdir -p /var/www/html
fi
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_SERVER } " = = true ] ] ; then
# Set the owner and permissions
chown ${ LIGHTTPD_USER } :${ LIGHTTPD_GROUP } /var/www/html
chmod 775 /var/www/html
# Give pihole access to the Web server group
usermod -a -G ${ LIGHTTPD_GROUP } pihole
# If the lighttpd command is executable,
if [ [ -x " $( command -v lighty-enable-mod) " ] ] ; then
# enable fastcgi and fastcgi-php
lighty-enable-mod fastcgi fastcgi-php > /dev/null || true
else
2017-12-11 04:51:54 +00:00
# Otherwise, show info about installing them
2018-04-15 01:08:16 +00:00
echo -e " ${ INFO } Warning: 'lighty-enable-mod' utility not found
Please ensure fastcgi is enabled if you experience issues\\ n"
fi
2017-12-11 04:51:54 +00:00
fi
fi
# For updates and unattended install.
if [ [ " ${ useUpdateVars } " = = true ] ] ; then
accountForRefactor
2016-12-21 01:22:57 +00:00
fi
2017-12-11 04:51:54 +00:00
# Install base files and web interface
2016-12-21 01:22:57 +00:00
installScripts
2017-12-11 04:51:54 +00:00
# Install config files
2016-12-21 01:22:57 +00:00
installConfigs
2017-07-07 00:25:56 +00:00
# If the user wants to install the dashboard,
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_INTERFACE } " = = true ] ] ; then
2017-07-07 00:25:56 +00:00
# do so
2017-01-28 15:25:02 +00:00
installPiholeWeb
fi
2017-07-07 00:25:56 +00:00
# Install the cron file
2016-12-21 01:22:57 +00:00
installCron
2017-07-07 00:25:56 +00:00
# Install the logrotate file
2017-01-27 13:16:24 +00:00
installLogrotate
2017-07-07 00:25:56 +00:00
# Check if FTL is installed
2017-07-26 17:00:08 +00:00
FTLdetect || echo -e " ${ CROSS } FTL Engine not installed "
2017-07-07 00:25:56 +00:00
# Configure the firewall
2017-12-11 04:51:54 +00:00
if [ [ " ${ useUpdateVars } " = = false ] ] ; then
configureFirewall
2017-01-28 15:25:02 +00:00
fi
2016-08-19 21:45:24 +00:00
2017-12-11 04:51:54 +00:00
# Update setupvars.conf with any variables that may or may not have been changed during the install
2017-07-26 13:34:40 +00:00
finalExports
2016-08-19 21:45:24 +00:00
}
2016-12-23 16:53:42 +00:00
2017-07-07 00:25:56 +00:00
# SELinux
2016-12-23 16:27:52 +00:00
checkSelinux( ) {
2017-07-07 00:25:56 +00:00
# If the getenforce command exists,
2016-12-27 19:53:23 +00:00
if command -v getenforce & > /dev/null; then
2017-07-07 00:25:56 +00:00
# Store the current mode in a variable
2016-12-23 17:16:03 +00:00
enforceMode = $( getenforce)
2017-07-26 17:00:08 +00:00
echo -e " \\n ${ INFO } SELinux mode detected: ${ enforceMode } "
2017-07-07 00:25:56 +00:00
# If it's enforcing,
2016-12-23 17:16:03 +00:00
if [ [ " ${ enforceMode } " = = "Enforcing" ] ] ; then
2017-07-07 00:25:56 +00:00
# Explain Pi-hole does not support it yet
2017-07-26 17:00:08 +00:00
whiptail --defaultno --title "SELinux Enforcing Detected" --yesno "SELinux is being ENFORCED on your system! \\n\\nPi-hole currently does not support SELinux, but you may still continue with the installation.\\n\\nNote: Web Admin will not be fully functional unless you set your policies correctly\\n\\nContinue installing Pi-hole?" ${ r } ${ c } || \
{ echo -e " \\n ${ COL_LIGHT_RED } SELinux Enforcing detected, exiting installer ${ COL_NC } " ; exit 1; }
echo -e " ${ INFO } Continuing installation with SELinux Enforcing
${ INFO } Please refer to official SELinux documentation to create a custom policy"
2016-12-21 01:22:57 +00:00
fi
fi
2015-11-07 18:07:50 +00:00
}
2017-07-07 00:25:56 +00:00
# Installation complete message with instructions for the user
2016-01-27 06:11:38 +00:00
displayFinalMessage( ) {
2017-07-07 00:25:56 +00:00
# If
2017-07-26 17:00:08 +00:00
if [ [ " ${# 1 } " -gt 0 ] ] ; then
2017-05-23 08:44:11 +00:00
pwstring = " $1 "
2017-07-07 00:25:56 +00:00
# else, if the dashboard password in the setup variables exists,
2017-05-23 08:44:11 +00:00
elif [ [ $( grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) -gt 0 ] ] ; then
2017-07-07 00:25:56 +00:00
# set a variable for evaluation later
2017-05-23 08:44:11 +00:00
pwstring = "unchanged"
else
2017-07-07 00:25:56 +00:00
# set a variable for evaluation later
2017-05-23 08:44:11 +00:00
pwstring = "NOT SET"
fi
2017-07-07 00:25:56 +00:00
# If the user wants to install the dashboard,
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_INTERFACE } " = = true ] ] ; then
2017-07-07 00:25:56 +00:00
# Store a message in a variable and display it
2017-01-28 15:43:33 +00:00
additional = " View the web interface at http://pi.hole/admin or http:// ${ IPV4_ADDRESS %/* } /admin
2017-05-23 08:44:11 +00:00
Your Admin Webpage login password is ${ pwstring } "
2017-01-28 15:43:33 +00:00
fi
2016-12-21 01:22:57 +00:00
# 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:
2016-01-01 02:26:05 +00:00
2016-11-01 09:45:22 +00:00
IPv4: ${ IPV4_ADDRESS %/* }
2017-01-01 15:10:14 +00:00
IPv6: ${ IPV6_ADDRESS :- "Not Configured" }
2016-01-01 02:26:05 +00:00
2016-04-03 23:05:11 +00:00
If you set a new IP address, you should restart the Pi.
2016-01-01 02:26:05 +00:00
2016-05-25 22:55:36 +00:00
The install log is in /etc/pihole.
2016-12-15 13:10:55 +00:00
2017-01-28 15:43:33 +00:00
${ additional } " ${ r } ${ c }
2016-08-19 21:31:11 +00:00
}
2016-10-20 02:47:45 +00:00
update_dialogs( ) {
2017-07-07 00:25:56 +00:00
# If pihole -r "reconfigure" option was selected,
2017-07-26 17:00:08 +00:00
if [ [ " ${ reconfigure } " = true ] ] ; then
2017-07-07 00:25:56 +00:00
# set some variables that will be used
2016-12-21 01:22:57 +00:00
opt1a = "Repair"
opt1b = "This will retain existing settings"
strAdd = "You will remain on the same version"
2017-12-11 04:51:54 +00:00
# Otherwise,
2016-12-21 01:22:57 +00:00
else
2017-07-07 00:25:56 +00:00
# set some variables with different values
2016-12-21 01:22:57 +00:00
opt1a = "Update"
opt1b = "This will retain existing settings."
strAdd = "You will be updated to the latest version."
fi
opt2a = "Reconfigure"
2018-04-17 18:46:36 +00:00
opt2b = "This will reset your Pi-hole and allow you to enter new settings."
2016-12-21 01:22:57 +00:00
2017-07-07 00:25:56 +00:00
# Display the information to the user
2017-07-26 17:00:08 +00:00
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 \
2016-12-21 01:22:57 +00:00
" ${ opt1a } " " ${ opt1b } " \
2017-01-09 02:46:15 +00:00
" ${ opt2a } " " ${ opt2b } " 3>& 2 2>& 1 1>& 3) || \
2017-06-21 11:49:05 +00:00
{ echo -e " ${ COL_LIGHT_RED } Cancel was selected, exiting installer ${ COL_NC } " ; exit 1; }
2017-01-09 02:46:15 +00:00
2017-11-05 09:18:39 +00:00
# Set the variable based on if the user chooses
2017-01-09 02:46:15 +00:00
case ${ UpdateCmd } in
2017-07-07 00:25:56 +00:00
# repair, or
2017-01-09 02:46:15 +00:00
${ opt1a } )
2017-07-26 17:00:08 +00:00
echo -e " ${ INFO } ${ opt1a } option selected "
2017-01-09 02:46:15 +00:00
useUpdateVars = true
; ;
2017-11-05 09:16:56 +00:00
# reconfigure,
2017-01-09 02:46:15 +00:00
${ opt2a } )
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } ${ opt2a } option selected "
2017-01-09 02:46:15 +00:00
useUpdateVars = false
; ;
2016-12-21 01:22:57 +00:00
esac
2016-01-01 02:26:05 +00:00
}
2018-05-01 20:59:12 +00:00
check_download_exists( ) {
status = $( curl --head --silent " https://ftl.pi-hole.net/ ${ 1 } " | head -n 1)
if grep -q "404" <<< " $status " ; then
return 1
else
return 0
fi
}
fully_fetch_repo( ) {
# Add upstream branches to shallow clone
local directory = " ${ 1 } "
cd " ${ directory } " || return 1
if is_repo " ${ directory } " ; then
git remote set-branches origin '*' || return 1
git fetch --quiet || return 1
else
return 1
fi
return 0
}
get_available_branches( ) {
# Return available branches
local directory
directory = " ${ 1 } "
local output
cd " ${ directory } " || return 1
# Get reachable remote branches, but store STDERR as STDOUT variable
output = $( { git remote show origin | grep 'tracked' | sed 's/tracked//;s/ //g' ; } 2>& 1 )
echo " $output "
return
}
fetch_checkout_pull_branch( ) {
# Check out specified branch
local directory
directory = " ${ 1 } "
local branch
branch = " ${ 2 } "
# Set the reference for the requested branch, fetch, check it put and pull it
cd " ${ directory } " || return 1
git remote set-branches origin " ${ branch } " || return 1
git stash --all --quiet & > /dev/null || true
git clean --quiet --force -d || true
git fetch --quiet || return 1
checkout_pull_branch " ${ directory } " " ${ branch } " || return 1
}
checkout_pull_branch( ) {
# Check out specified branch
local directory
directory = " ${ 1 } "
local branch
branch = " ${ 2 } "
local oldbranch
cd " ${ directory } " || return 1
oldbranch = " $( git symbolic-ref HEAD) "
str = " Switching to branch: ' ${ branch } ' from ' ${ oldbranch } ' "
echo -ne " ${ INFO } $str "
git checkout " ${ branch } " --quiet || return 1
echo -e " ${ OVER } ${ TICK } $str "
git_pull = $( git pull || return 1)
if [ [ " $git_pull " = = *"up-to-date" * ] ] ; then
echo -e " ${ INFO } ${ git_pull } "
else
echo -e " $git_pull \\n "
fi
return 0
}
2017-01-28 15:15:42 +00:00
clone_or_update_repos( ) {
2017-07-07 00:25:56 +00:00
# If the user wants to reconfigure,
2017-05-21 20:47:26 +00:00
if [ [ " ${ reconfigure } " = = true ] ] ; then
2017-06-21 11:49:05 +00:00
echo " ${ INFO } Performing reconfiguration, skipping download of local repos "
2017-07-07 00:25:56 +00:00
# Reset the Core repo
2017-05-22 21:43:52 +00:00
resetRepo ${ PI_HOLE_LOCAL_REPO } || \
2017-06-21 11:49:05 +00:00
{ echo -e " ${ COL_LIGHT_RED } Unable to reset ${ PI_HOLE_LOCAL_REPO } , exiting installer ${ COL_NC } " ; \
2017-05-22 21:43:52 +00:00
exit 1; \
}
2017-07-07 00:25:56 +00:00
# If the Web interface was installed,
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_INTERFACE } " = = true ] ] ; then
2017-07-07 00:25:56 +00:00
# reset it's repo
2017-05-22 21:43:52 +00:00
resetRepo ${ webInterfaceDir } || \
2017-06-21 11:49:05 +00:00
{ echo -e " ${ COL_LIGHT_RED } Unable to reset ${ webInterfaceDir } , exiting installer ${ COL_NC } " ; \
2017-01-28 15:15:42 +00:00
exit 1; \
}
2017-05-22 21:43:52 +00:00
fi
2017-07-07 00:25:56 +00:00
# Otherwise, a repair is happening
2017-05-21 20:47:26 +00:00
else
2017-07-07 00:25:56 +00:00
# so get git files for Core
2017-05-21 20:47:26 +00:00
getGitFiles ${ PI_HOLE_LOCAL_REPO } ${ piholeGitUrl } || \
2017-07-26 17:00:08 +00:00
{ echo -e " ${ COL_LIGHT_RED } Unable to clone ${ piholeGitUrl } into ${ PI_HOLE_LOCAL_REPO } , unable to continue ${ COL_NC } " ; \
2017-05-21 20:47:26 +00:00
exit 1; \
}
2017-07-07 00:25:56 +00:00
# If the Web interface was installed,
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_INTERFACE } " = = true ] ] ; then
2017-07-07 00:25:56 +00:00
# get the Web git files
2017-01-28 15:15:42 +00:00
getGitFiles ${ webInterfaceDir } ${ webInterfaceGitUrl } || \
2017-06-21 11:49:05 +00:00
{ echo -e " ${ COL_LIGHT_RED } Unable to clone ${ webInterfaceGitUrl } into ${ webInterfaceDir } , exiting installer ${ COL_NC } " ; \
2017-01-28 15:15:42 +00:00
exit 1; \
}
fi
2017-05-21 20:47:26 +00:00
fi
2017-01-28 15:15:42 +00:00
}
2018-02-23 04:13:38 +00:00
# Download FTL binary to random temp directory and install FTL binary
2017-02-20 16:24:19 +00:00
FTLinstall( ) {
2017-07-07 00:25:56 +00:00
# Local, named variables
2017-02-20 16:24:19 +00:00
local binary = " ${ 1 } "
2017-02-20 18:25:17 +00:00
local latesttag
2017-07-12 21:02:07 +00:00
local str = "Downloading and Installing FTL"
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } ${ str } ... "
2017-02-20 16:24:19 +00:00
2017-07-07 00:25:56 +00:00
# Find the latest version tag for FTL
2017-02-20 18:25:17 +00:00
latesttag = $( curl -sI https://github.com/pi-hole/FTL/releases/latest | grep "Location" | awk -F '/' '{print $NF}' )
2017-02-20 19:49:20 +00:00
# Tags should always start with v, check for that.
if [ [ ! " ${ latesttag } " = = v* ] ] ; then
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ CROSS } ${ str } "
echo -e " ${ COL_LIGHT_RED } Error: Unable to get latest release location from GitHub ${ COL_NC } "
2017-02-20 16:24:19 +00:00
return 1
fi
2017-07-12 21:02:07 +00:00
2018-02-23 04:13:38 +00:00
# Move into the temp ftl directory
2018-03-07 22:19:11 +00:00
pushd " $( mktemp -d) " > /dev/null || { echo "Unable to make temporary directory for FTL binary download" ; return 1; }
2018-02-23 04:13:38 +00:00
2018-02-18 12:07:22 +00:00
# Always replace pihole-FTL.service
install -T -m 0755 " ${ PI_HOLE_LOCAL_REPO } /advanced/pihole-FTL.service " "/etc/init.d/pihole-FTL"
2018-03-06 18:44:57 +00:00
local ftlBranch
local url
local ftlBranch
2018-03-18 00:38:34 +00:00
2018-03-06 18:44:57 +00:00
if [ [ -f "/etc/pihole/ftlbranch" ] ] ; then
ftlBranch = $( </etc/pihole/ftlbranch)
else
ftlBranch = "master"
fi
2018-03-18 00:38:34 +00:00
2018-03-06 18:44:57 +00:00
# Determine which version of FTL to download
if [ [ " ${ ftlBranch } " = = "master" ] ] ; then
url = " https://github.com/pi-hole/FTL/releases/download/ ${ latesttag % $'\r' } "
else
url = " https://ftl.pi-hole.net/ ${ ftlBranch } "
fi
2017-07-07 00:25:56 +00:00
# If the download worked,
2018-03-06 18:44:57 +00:00
if curl -sSL --fail " ${ url } / ${ binary } " -o " ${ binary } " ; then
2017-07-07 00:25:56 +00:00
# get sha1 of the binary we just downloaded for verification.
2018-03-18 00:38:34 +00:00
curl -sSL --fail " ${ url } / ${ binary } .sha1 " -o " ${ binary } .sha1 "
2018-03-07 23:31:28 +00:00
2017-07-07 00:25:56 +00:00
# If we downloaded binary file (as opposed to text),
2017-02-20 23:27:24 +00:00
if sha1sum --status --quiet -c " ${ binary } " .sha1; then
2017-02-20 22:44:34 +00:00
echo -n "transferred... "
2017-07-07 00:25:56 +00:00
# Stop FTL
2017-02-21 15:42:52 +00:00
stop_service pihole-FTL & > /dev/null
2017-07-07 00:25:56 +00:00
# Install the new version with the correct permissions
2018-02-23 04:13:38 +00:00
install -T -m 0755 " ${ binary } " /usr/bin/pihole-FTL
2017-07-07 00:25:56 +00:00
# Move back into the original directory the user was in
2018-03-07 22:23:05 +00:00
popd > /dev/null || { echo "Unable to return to original directory after FTL binary download." ; return 1; }
2017-07-07 00:25:56 +00:00
# Install the FTL service
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } ${ str } "
2018-05-03 20:16:31 +00:00
# dnsmasq can now be stopped and disabled if it exists
if which dnsmasq > /dev/null; then
if check_service_active "dnsmasq" ; then
echo " ${ INFO } FTL can now resolve DNS Queries without dnsmasq running separately "
stop_service dnsmasq
disable_service dnsmasq
fi
2018-04-30 22:42:41 +00:00
fi
2018-03-18 00:38:34 +00:00
2018-04-30 22:42:41 +00:00
#ensure /etc/dnsmasq.conf contains `conf-dir=/etc/dnsmasq.d`
confdir = "conf-dir=/etc/dnsmasq.d"
conffile = "/etc/dnsmasq.conf"
if ! grep -q " $confdir " " $conffile " ; then
echo " $confdir " >> " $conffile "
2018-03-07 23:31:28 +00:00
fi
2018-04-30 22:42:41 +00:00
2017-02-20 17:36:24 +00:00
return 0
2017-12-11 04:51:54 +00:00
# Otherwise,
2017-02-20 17:36:24 +00:00
else
2018-02-23 04:13:38 +00:00
# the download failed, so just go back to the original directory
2018-03-07 22:19:11 +00:00
popd > /dev/null || { echo "Unable to return to original directory after FTL binary download." ; return 1; }
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ CROSS } ${ str } "
echo -e " ${ COL_LIGHT_RED } Error: Download of binary from Github failed ${ COL_NC } "
2017-02-20 17:36:24 +00:00
return 1
2018-03-18 00:38:34 +00:00
fi
2017-07-07 00:25:56 +00:00
# Otherwise,
2017-02-20 19:45:58 +00:00
else
2018-03-07 22:19:11 +00:00
popd > /dev/null || { echo "Unable to return to original directory after FTL binary download." ; return 1; }
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ CROSS } ${ str } "
2017-07-07 00:25:56 +00:00
# The URL could not be found
2017-06-21 11:49:05 +00:00
echo -e " ${ COL_LIGHT_RED } Error: URL not found ${ COL_NC } "
2018-02-23 04:13:38 +00:00
return 1
2017-02-20 16:24:19 +00:00
fi
}
2018-04-02 20:53:32 +00:00
get_binary_name( ) {
# Local, named variables
2017-02-20 16:24:19 +00:00
local machine
2017-07-07 00:25:56 +00:00
# Store architecture in a variable
2017-02-21 17:14:49 +00:00
machine = $( uname -m)
2017-02-13 09:29:27 +00:00
2017-06-21 11:49:05 +00:00
local str = "Detecting architecture"
echo -ne " ${ INFO } ${ str } ... "
2017-07-07 00:25:56 +00:00
# If the machine is arm or aarch
2017-07-26 17:00:08 +00:00
if [ [ " ${ machine } " = = "arm" * || " ${ machine } " = = *"aarch" * ] ] ; then
2017-02-13 09:29:27 +00:00
# ARM
2017-07-07 00:25:56 +00:00
#
2017-07-26 17:00:08 +00:00
local rev
rev = $( uname -m | sed "s/[^0-9]//g;" )
2017-07-07 00:25:56 +00:00
#
2017-07-26 17:00:08 +00:00
local lib
lib = $( ldd /bin/ls | grep -E '^\s*/lib' | awk '{ print $1 }' )
2017-07-07 00:25:56 +00:00
#
2017-07-26 17:00:08 +00:00
if [ [ " ${ lib } " = = "/lib/ld-linux-aarch64.so.1" ] ] ; then
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Detected ARM-aarch64 architecture "
2017-07-07 00:25:56 +00:00
# set the binary to be used
2017-02-13 09:29:27 +00:00
binary = "pihole-FTL-aarch64-linux-gnu"
2017-07-07 00:25:56 +00:00
#
2017-07-26 17:00:08 +00:00
elif [ [ " ${ lib } " = = "/lib/ld-linux-armhf.so.3" ] ] ; then
2017-07-07 00:25:56 +00:00
#
2017-07-26 17:00:08 +00:00
if [ [ " ${ rev } " -gt 6 ] ] ; then
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Detected ARM-hf architecture (armv7+) "
2017-07-07 00:25:56 +00:00
# set the binary to be used
2017-02-20 10:14:23 +00:00
binary = "pihole-FTL-arm-linux-gnueabihf"
2017-07-07 00:25:56 +00:00
# Otherwise,
2017-02-20 10:14:23 +00:00
else
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Detected ARM-hf architecture (armv6 or lower) Using ARM binary "
2017-07-07 00:25:56 +00:00
# set the binary to be used
2017-02-20 10:14:23 +00:00
binary = "pihole-FTL-arm-linux-gnueabi"
fi
2017-02-13 09:29:27 +00:00
else
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Detected ARM architecture "
2017-07-07 00:25:56 +00:00
# set the binary to be used
2017-02-13 09:29:27 +00:00
binary = "pihole-FTL-arm-linux-gnueabi"
fi
2017-07-26 17:00:08 +00:00
elif [ [ " ${ machine } " = = "ppc" ] ] ; then
2017-06-19 20:28:04 +00:00
# PowerPC
2017-07-26 17:00:08 +00:00
echo -e " ${ OVER } ${ TICK } Detected PowerPC architecture "
2017-07-07 00:25:56 +00:00
# set the binary to be used
2017-06-19 20:28:04 +00:00
binary = "pihole-FTL-powerpc-linux-gnu"
2017-07-26 17:00:08 +00:00
elif [ [ " ${ machine } " = = "x86_64" ] ] ; then
2017-02-13 09:29:27 +00:00
# 64bit
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Detected x86_64 architecture "
2017-07-07 00:25:56 +00:00
# set the binary to be used
2017-02-13 09:29:27 +00:00
binary = "pihole-FTL-linux-x86_64"
else
# Something else - we try to use 32bit executable and warn the user
2017-07-26 17:00:08 +00:00
if [ [ ! " ${ machine } " = = "i686" ] ] ; then
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ CROSS } ${ str } ...
2017-07-26 17:00:08 +00:00
${ COL_LIGHT_RED } Not able to detect architecture ( unknown: ${ machine } ) , trying 32bit executable${ COL_NC }
Contact Pi-hole Support if you experience issues ( e.g: FTL not running) "
2017-02-13 15:50:48 +00:00
else
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Detected 32bit (i686) architecture "
2017-02-13 13:42:11 +00:00
fi
2017-02-13 09:29:27 +00:00
binary = "pihole-FTL-linux-x86_32"
fi
2018-04-02 20:53:32 +00:00
}
2017-02-13 09:29:27 +00:00
2018-04-02 20:53:32 +00:00
FTLcheckUpdate( )
{
2018-04-02 22:22:06 +00:00
get_binary_name
#In the next section we check to see if FTL is already installed (in case of pihole -r).
#If the installed version matches the latest version, then check the installed sha1sum of the binary vs the remote sha1sum. If they do not match, then download
echo -e " ${ INFO } Checking for existing FTL binary... "
local ftlLoc
ftlLoc = $( which pihole-FTL 2>/dev/null)
2018-03-18 00:38:34 +00:00
2018-03-06 18:44:57 +00:00
local ftlBranch
2018-03-18 00:38:34 +00:00
2018-03-06 18:44:57 +00:00
if [ [ -f "/etc/pihole/ftlbranch" ] ] ; then
ftlBranch = $( </etc/pihole/ftlbranch)
else
ftlBranch = "master"
fi
2018-04-02 20:53:32 +00:00
local remoteSha1
local localSha1
2018-05-03 20:16:31 +00:00
# if dnsmasq exists and is running at this point, force reinstall of FTL Binary
if which dnsmasq > /dev/null; then
if check_service_active "dnsmasq" ; then
return 0
fi
2018-04-30 22:50:35 +00:00
fi
2018-03-06 18:44:57 +00:00
if [ [ ! " ${ ftlBranch } " = = "master" ] ] ; then
2018-05-01 20:59:12 +00:00
#Check whether or not the binary for this FTL branch actually exists. If not, then there is no update!
local path
path = " ${ ftlBranch } / ${ binary } "
# shellcheck disable=SC1090
if ! check_download_exists " $path " ; then
echo -e " ${ INFO } Branch \" ${ ftlBranch } \" is not available.\\n ${ INFO } Use ${ COL_LIGHT_GREEN } pihole checkout ftl [branchname] ${ COL_NC } to switch to a valid branch. "
return 2
fi
2018-04-02 20:53:32 +00:00
if [ [ ${ ftlLoc } ] ] ; then
# We already have a pihole-FTL binary downloaded.
# Alt branches don't have a tagged version against them, so just confirm the checksum of the local vs remote to decide whether we download or not
remoteSha1 = $( curl -sSL --fail " https://ftl.pi-hole.net/ ${ ftlBranch } / ${ binary } .sha1 " | cut -d ' ' -f 1)
localSha1 = $( sha1sum " $( which pihole-FTL) " | cut -d ' ' -f 1)
if [ [ " ${ remoteSha1 } " != " ${ localSha1 } " ] ] ; then
echo -e " ${ INFO } Checksums do not match, downloading from ftl.pi-hole.net. "
return 0
else
echo -e " ${ INFO } Checksum of installed binary matches remote. No need to download! "
return 1
fi
else
return 0
fi
2018-03-06 18:44:57 +00:00
else
if [ [ ${ ftlLoc } ] ] ; then
2018-03-06 18:49:38 +00:00
local FTLversion
FTLversion = $( /usr/bin/pihole-FTL tag)
local FTLlatesttag
FTLlatesttag = $( curl -sI https://github.com/pi-hole/FTL/releases/latest | grep 'Location' | awk -F '/' '{print $NF}' | tr -d '\r\n' )
2018-03-06 18:44:57 +00:00
if [ [ " ${ FTLversion } " != " ${ FTLlatesttag } " ] ] ; then
2018-04-02 20:53:32 +00:00
return 0
2018-03-06 18:44:57 +00:00
else
echo -e " ${ INFO } Latest FTL Binary already installed ( ${ FTLlatesttag } ). Confirming Checksum... "
2017-07-24 22:22:04 +00:00
2018-03-06 18:49:38 +00:00
remoteSha1 = $( curl -sSL --fail " https://github.com/pi-hole/FTL/releases/download/ ${ FTLversion % $'\r' } / ${ binary } .sha1 " | cut -d ' ' -f 1)
localSha1 = $( sha1sum " $( which pihole-FTL) " | cut -d ' ' -f 1)
2017-07-12 21:02:07 +00:00
2018-03-06 18:44:57 +00:00
if [ [ " ${ remoteSha1 } " != " ${ localSha1 } " ] ] ; then
echo -e " ${ INFO } Corruption detected... "
2018-04-02 20:53:32 +00:00
return 0
2018-03-06 18:44:57 +00:00
else
echo -e " ${ INFO } Checksum correct. No need to download! "
2018-04-02 20:53:32 +00:00
return 1
2018-03-06 18:44:57 +00:00
fi
fi
else
2018-04-02 20:53:32 +00:00
return 0
2018-03-06 18:44:57 +00:00
fi
2017-07-25 21:49:06 +00:00
fi
2018-04-02 20:53:32 +00:00
}
# Detect suitable FTL binary platform
FTLdetect( ) {
echo ""
echo -e " ${ INFO } FTL Checks... "
if FTLcheckUpdate ; then
FTLinstall " ${ binary } " || return 1
fi
2018-03-07 23:31:28 +00:00
echo ""
2018-01-20 13:55:48 +00:00
}
2017-07-25 21:49:06 +00:00
2018-01-20 13:55:48 +00:00
make_temporary_log( ) {
# Create a random temporary file for the log
TEMPLOG = $( mktemp /tmp/pihole_temp.XXXXXX)
# Open handle 3 for templog
# https://stackoverflow.com/questions/18460186/writing-outputs-to-log-file-and-console
exec 3>" $TEMPLOG "
# Delete templog, but allow for addressing via file handle
# This lets us write to the log without having a temporary file on the drive, which
2018-01-20 14:20:06 +00:00
# is meant to be a security measure so there is not a lingering file on the drive during the install process
2018-01-20 13:55:48 +00:00
rm " $TEMPLOG "
}
2017-02-13 13:47:06 +00:00
2018-01-20 13:55:48 +00:00
copy_to_install_log( ) {
# Copy the contents of file descriptor 3 into the install log
# Since we use color codes such as '\e[1;33m', they should be removed
2018-01-20 14:20:06 +00:00
sed 's/ \[[0-9;]\{1,5\}m//g' < /proc/$$ /fd/3 > " ${ installLogLoc } "
2017-02-13 10:07:29 +00:00
}
2017-02-13 09:29:27 +00:00
2016-10-08 19:17:04 +00:00
main( ) {
2017-01-01 14:45:03 +00:00
######## FIRST CHECK ########
2017-07-07 00:25:56 +00:00
# Must be root to install
2017-06-21 11:49:05 +00:00
local str = "Root user check"
echo ""
2017-07-07 00:25:56 +00:00
# If the user's id is zero,
2017-07-26 17:00:08 +00:00
if [ [ " ${ EUID } " -eq 0 ] ] ; then
2017-07-07 00:25:56 +00:00
# they are root and all is good
2017-06-21 11:49:05 +00:00
echo -e " ${ TICK } ${ str } "
2018-01-20 13:13:55 +00:00
# Show the Pi-hole logo so people know it's genuine since the logo and name are trademarked
show_ascii_berry
2018-01-20 14:20:06 +00:00
make_temporary_log
2017-07-07 00:25:56 +00:00
# Otherwise,
2017-01-01 14:45:03 +00:00
else
2017-07-07 00:25:56 +00:00
# They do not have enough privileges, so let the user know
2017-06-21 11:49:05 +00:00
echo -e " ${ CROSS } ${ str }
2017-07-26 17:00:08 +00:00
${ COL_LIGHT_RED } Script called with non-root privileges${ COL_NC }
2018-01-27 12:36:11 +00:00
The Pi-hole requires elevated privileges to install and run
2017-07-26 17:00:08 +00:00
Please check the installer for any concerns regarding this requirement
Make sure to download this script from a trusted source\\ n"
2017-06-21 11:49:05 +00:00
echo -ne " ${ INFO } Sudo utility check "
2017-01-01 14:45:03 +00:00
2017-07-07 00:25:56 +00:00
# If the sudo command exists,
2017-01-01 14:45:03 +00:00
if command -v sudo & > /dev/null; then
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ TICK } Sudo utility check "
2017-07-07 00:25:56 +00:00
# Download the install script and run it with admin rights
2017-01-23 22:28:56 +00:00
exec curl -sSL https://raw.githubusercontent.com/pi-hole/pi-hole/master/automated%20install/basic-install.sh | sudo bash " $@ "
2017-01-01 14:45:03 +00:00
exit $?
2017-07-07 00:25:56 +00:00
# Otherwise,
2017-01-01 14:45:03 +00:00
else
2017-07-07 00:25:56 +00:00
# Let them know they need to run it as root
2017-06-21 11:49:05 +00:00
echo -e " ${ OVER } ${ CROSS } Sudo utility check
2017-07-26 17:00:08 +00:00
Sudo is needed for the Web Interface to run pihole commands\\ n
2017-06-21 11:49:05 +00:00
${ COL_LIGHT_RED } Please re-run this installer as root${ COL_NC } "
2017-01-01 14:45:03 +00:00
exit 1
fi
fi
2017-01-21 20:34:47 +00:00
# Check for supported distribution
distro_check
2017-07-07 00:25:56 +00:00
# If the setup variable file exists,
2017-07-26 17:00:08 +00:00
if [ [ -f " ${ setupVars } " ] ] ; then
2017-07-07 00:25:56 +00:00
# if it's running unattended,
2016-12-21 01:22:57 +00:00
if [ [ " ${ runUnattended } " = = true ] ] ; then
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } Performing unattended setup, no whiptail dialogs will be displayed "
2017-07-07 00:25:56 +00:00
# Use the setup variables
2016-12-21 01:22:57 +00:00
useUpdateVars = true
2017-07-07 00:25:56 +00:00
# Otherwise,
2016-12-21 01:22:57 +00:00
else
2017-07-07 00:25:56 +00:00
# show the available options (repair/reconfigure)
2016-12-21 01:22:57 +00:00
update_dialogs
fi
fi
# Start the installer
# Verify there is enough disk space for the install
if [ [ " ${ skipSpaceCheck } " = = true ] ] ; then
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } Skipping free disk space verification "
2016-12-21 01:22:57 +00:00
else
verifyFreeDiskSpace
fi
# Update package cache
2017-03-02 23:54:58 +00:00
update_package_cache || exit 1
2016-12-21 01:22:57 +00:00
# Notify user of package availability
notify_package_updates_available
# Install packages used by this installation script
install_dependent_packages INSTALLER_DEPS[ @]
2016-12-23 16:55:56 +00:00
# Check if SELinux is Enforcing
checkSelinux
2017-07-26 17:00:08 +00:00
if [ [ " ${ useUpdateVars } " = = false ] ] ; then
2016-12-21 01:22:57 +00:00
# Display welcome dialogs
welcomeDialogs
# Create directory for Pi-hole storage
mkdir -p /etc/pihole/
# Determine available interfaces
get_available_interfaces
# Find interfaces and let the user choose one
chooseInterface
# Decide what upstream DNS Servers to use
setDNS
2018-04-17 18:46:36 +00:00
# Give the user a choice of blocklists to include in their install. Or not.
chooseBlocklists
2016-12-23 04:34:38 +00:00
# Let the user decide if they want to block ads over IPv4 and/or IPv6
use4andor6
2017-01-28 14:38:54 +00:00
# Let the user decide if they want the web interface to be installed automatically
setAdminFlag
2016-12-21 01:22:57 +00:00
# Let the user decide if they want query logging enabled...
setLogging
else
2017-12-24 13:09:45 +00:00
# Source ${setupVars} to use predefined user variables in the functions
source ${ setupVars }
2017-12-11 04:51:54 +00:00
fi
# Clone/Update the repos
clone_or_update_repos
2017-12-24 13:09:45 +00:00
2017-12-11 04:51:54 +00:00
# Install the Core dependencies
local dep_install_list = ( " ${ PIHOLE_DEPS [@] } " )
if [ [ " ${ INSTALL_WEB_SERVER } " = = true ] ] ; then
# Install the Web dependencies
dep_install_list += ( " ${ PIHOLE_WEB_DEPS [@] } " )
fi
2017-01-28 18:39:15 +00:00
2017-12-11 04:51:54 +00:00
install_dependent_packages dep_install_list[ @]
unset dep_install_list
2018-04-15 01:08:16 +00:00
2017-12-11 04:51:54 +00:00
# On some systems, lighttpd is not enabled on first install. We need to enable it here if the user
# has chosen to install the web interface, else the `LIGHTTPD_ENABLED` check will fail
if [ [ " ${ INSTALL_WEB_SERVER } " = = true ] ] ; then
enable_service lighttpd
fi
2016-12-21 01:22:57 +00:00
2017-12-11 04:51:54 +00:00
if [ [ -x " $( command -v systemctl) " ] ] ; then
# Value will either be 1, if true, or 0
LIGHTTPD_ENABLED = $( systemctl is-enabled lighttpd | grep -c 'enabled' || true )
else
# Value will either be 1, if true, or 0
LIGHTTPD_ENABLED = $( service lighttpd status | awk '/Loaded:/ {print $0}' | grep -c 'enabled' || true )
2016-12-21 01:22:57 +00:00
fi
2017-12-11 04:51:54 +00:00
# Install and log everything to a file
installPihole | tee -a /proc/$$ /fd/3
2018-01-20 14:20:06 +00:00
# Copy the temp log file into final log location for storage
2018-01-20 13:55:48 +00:00
copy_to_install_log
2016-12-21 01:22:57 +00:00
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_INTERFACE } " = = true ] ] ; then
2017-01-28 15:25:02 +00:00
# Add password to web UI if there is none
pw = ""
2017-07-07 00:25:56 +00:00
# If no password is set,
2017-01-28 15:25:02 +00:00
if [ [ $( grep 'WEBPASSWORD' -c /etc/pihole/setupVars.conf) = = 0 ] ] ; then
2017-07-07 00:25:56 +00:00
# generate a random password
2017-01-28 15:25:02 +00:00
pw = $( tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 8)
2017-07-26 17:00:08 +00:00
# shellcheck disable=SC1091
2017-05-02 21:25:47 +00:00
. /opt/pihole/webpage.sh
2017-05-02 21:37:38 +00:00
echo " WEBPASSWORD= $( HashPassword ${ pw } ) " >> ${ setupVars }
2017-01-28 15:25:02 +00:00
fi
2016-12-21 01:22:57 +00:00
fi
2018-05-20 22:16:53 +00:00
# Check for and disable systemd-resolved-DNSStubListener before reloading resolved
# DNSStubListener needs to remain in place for installer to download needed files,
# so this change needs to be made after installation is complete,
# but before starting or resarting the dnsmasq or ftl services
disable_resolved_stublistener
2017-01-28 15:25:02 +00:00
2017-07-07 00:25:56 +00:00
# If the Web server was installed,
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_SERVER } " = = true ] ] ; then
2017-07-16 15:44:14 +00:00
if [ [ " ${ LIGHTTPD_ENABLED } " = = "1" ] ] ; then
start_service lighttpd
enable_service lighttpd
else
echo -e " ${ INFO } Lighttpd is disabled, skipping service restart "
fi
2017-01-28 15:25:02 +00:00
fi
2018-05-20 22:16:53 +00:00
echo -e " ${ INFO } Restarting services... "
# Start services
2018-05-14 09:38:12 +00:00
2017-07-07 00:25:56 +00:00
# Enable FTL
2017-02-21 10:18:47 +00:00
start_service pihole-FTL
enable_service pihole-FTL
2017-09-20 07:29:11 +00:00
# Download and compile the aggregated block list
runGravity
2017-10-28 13:40:48 +00:00
# Force an update of the updatechecker
. /opt/pihole/updatecheck.sh
2017-12-28 17:41:22 +00:00
. /opt/pihole/updatecheck.sh x remote
2017-10-28 13:40:48 +00:00
2017-07-07 00:25:56 +00:00
#
2017-01-28 15:25:02 +00:00
if [ [ " ${ useUpdateVars } " = = false ] ] ; then
displayFinalMessage " ${ pw } "
fi
2017-06-29 01:18:52 +00:00
2017-07-07 00:25:56 +00:00
# If the Web interface was installed,
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_INTERFACE } " = = true ] ] ; then
2017-07-07 00:25:56 +00:00
# If there is a password,
2017-06-21 11:49:05 +00:00
if ( ( ${# pw } > 0 ) ) ; then
2017-07-07 00:25:56 +00:00
# display the password
2017-06-21 11:49:05 +00:00
echo -e " ${ INFO } Web Interface password: ${ COL_LIGHT_GREEN } ${ pw } ${ COL_NC }
2017-07-26 17:00:08 +00:00
This can be changed using 'pihole -a -p' \\ n"
2017-06-21 11:49:05 +00:00
fi
fi
2017-01-28 15:25:02 +00:00
2017-07-07 00:25:56 +00:00
#
2016-12-21 01:22:57 +00:00
if [ [ " ${ useUpdateVars } " = = false ] ] ; then
2017-07-07 00:25:56 +00:00
# If the Web interface was installed,
2018-04-15 01:08:16 +00:00
if [ [ " ${ INSTALL_WEB_INTERFACE } " = = true ] ] ; then
2017-06-21 11:49:05 +00:00
echo -e " View the web interface at http://pi.hole/admin or http:// ${ IPV4_ADDRESS %/* } /admin "
echo ""
2017-01-28 15:25:02 +00:00
fi
2017-07-07 00:25:56 +00:00
# Explain to the user how to use Pi-hole as their DNS server
2017-06-21 11:49:05 +00:00
echo " You may now configure your devices to use the Pi-hole as their DNS server"
[ [ -n " ${ IPV4_ADDRESS %/* } " ] ] && echo -e " ${ INFO } Pi-hole DNS (IPv4): ${ IPV4_ADDRESS %/* } "
[ [ -n " ${ IPV6_ADDRESS } " ] ] && echo -e " ${ INFO } Pi-hole DNS (IPv6): ${ IPV6_ADDRESS } "
echo -e " If you set a new IP address, please restart the server running the Pi-hole"
2017-07-07 00:25:56 +00:00
#
2017-06-21 11:49:05 +00:00
INSTALL_TYPE = "Installation"
2016-12-21 01:22:57 +00:00
else
2017-07-07 00:25:56 +00:00
#
2017-06-21 11:49:05 +00:00
INSTALL_TYPE = "Update"
2016-12-21 01:22:57 +00:00
fi
2017-06-29 01:18:52 +00:00
2017-07-07 00:25:56 +00:00
# Display where the log file is
2018-01-20 16:45:41 +00:00
echo -e " \\n ${ INFO } The install log is located at: ${ installLogLoc }
2017-06-21 11:49:05 +00:00
${ COL_LIGHT_GREEN } ${ INSTALL_TYPE } Complete! ${ COL_NC } "
2017-07-26 13:34:40 +00:00
2018-04-02 20:53:32 +00:00
if [ [ " ${ INSTALL_TYPE } " = = "Update" ] ] ; then
echo ""
/usr/local/bin/pihole version --current
fi
2016-10-08 19:17:04 +00:00
}
2017-07-07 00:25:56 +00:00
#
2016-11-04 03:34:04 +00:00
if [ [ " ${ PH_TEST } " != true ] ] ; then
2016-12-21 01:22:57 +00:00
main " $@ "
2016-10-11 04:14:39 +00:00
fi