2015-11-25 22:43:59 +01:00
#!/usr/bin/env bash
2015-10-28 23:29:34 +01:00
# Pi-hole: A black hole for Internet advertisements
2016-01-30 21:12:40 +01:00
# (c) 2015, 2016 by Jacob Salmela
2015-10-28 23:29:34 +01:00
# Network-wide ad blocking via your Raspberry Pi
2016-01-30 21:12:40 +01:00
# http://pi-hole.net
# Installs Pi-hole
2015-12-06 15:31:49 +01:00
#
# Pi-hole is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
2016-01-30 21:12:40 +01:00
2015-10-28 23:29:34 +01:00
# pi-hole.net/donate
2015-06-14 05:14:21 +02:00
#
2015-10-28 23:29:34 +01:00
# Install with this command (from your Pi):
2015-06-14 05:14:21 +02:00
#
2015-10-28 23:29:34 +01:00
# curl -L install.pi-hole.net | bash
2015-06-14 05:14:21 +02:00
2016-10-10 11:24:03 +02:00
set -e
2015-10-28 23:29:34 +01:00
######## VARIABLES #########
2015-10-31 15:19:57 +01:00
tmpLog = /tmp/pihole-install.log
2015-10-31 15:15:57 +01:00
instalLogLoc = /etc/pihole/install.log
2016-08-21 18:57:11 +02:00
setupVars = /etc/pihole/setupVars.conf
2015-10-31 15:15:57 +01:00
2016-01-24 04:31:12 +01: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 08:14:25 +01:00
PI_HOLE_LOCAL_REPO = "/etc/.pihole"
PI_HOLE_FILES = ( chronometer list piholeDebug piholeLogFlush setupLCD update version)
2016-08-19 23:31:11 +02:00
useUpdateVars = false
2016-01-23 01:13:16 +01:00
2016-11-01 10:45:22 +01:00
IPV4_ADDRESS = ""
IPV6_ADDRESS = ""
2016-11-01 17:46:54 +01:00
QUERY_LOGGING = true
2016-10-10 14:45:37 +02:00
2016-10-26 16:08:23 +02:00
# Find the rows and columns will default to 80x24 is it can not be detected
2016-11-02 13:17:28 +01:00
screen_size = $( stty size 2>/dev/null || echo 24 80)
2016-10-26 16:08:23 +02:00
rows = $( echo $screen_size | awk '{print $1}' )
columns = $( echo $screen_size | awk '{print $2}' )
2015-10-28 23:29:34 +01: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 16:44:15 +02:00
# Unless the screen is tiny
r = $(( r < 20 ? 20 : r ))
c = $(( c < 70 ? 70 : c ))
2015-10-28 23:29:34 +01:00
2016-10-15 21:52:20 +02:00
######## Undocumented Flags. Shhh ########
2016-10-15 21:43:03 +02:00
skipSpaceCheck = false
2016-10-15 22:12:13 +02:00
reconfigure = false
2016-10-15 21:43:03 +02:00
runUnattended = false
2016-01-23 23:25:30 +01:00
######## FIRST CHECK ########
# Must be root to install
2016-01-24 17:33:53 +01:00
echo ":::"
2016-10-22 08:57:47 +02:00
if [ [ ${ EUID } -eq 0 ] ] ; then
2016-11-02 13:17:28 +01:00
echo "::: You are root."
2015-06-21 14:50:02 +02:00
else
2016-11-02 13:17:28 +01:00
echo "::: Script called with non-root privileges. The Pi-hole installs server packages and configures"
echo "::: system networking, it requires elevated rights. Please check the contents of the script for"
echo "::: any concerns with this requirement. Please be sure to download this script from a trusted source."
echo ":::"
echo "::: Detecting the presence of the sudo utility for continuation of this install..."
if [ -x " $( command -v sudo) " ] ; then
echo "::: Utility sudo located."
exec curl -sSL https://install.pi-hole.net | sudo bash " $@ "
exit $?
else
echo "::: sudo is needed for the Web interface to run pihole commands. Please run this script as root and it will be automatically installed."
exit 1
fi
2015-06-21 14:50:02 +02:00
fi
2015-10-28 23:29:34 +01:00
2016-08-19 23:31:11 +02:00
# Compatibility
2016-09-05 16:52:09 +02:00
2016-11-02 08:51:38 +01:00
if [ [ $( command -v apt-get) ] ] ; then
2016-11-02 13:17:28 +01:00
#Debian Family
#############################################
PKG_MANAGER = "apt-get"
PKG_CACHE = "/var/lib/apt/lists/"
UPDATE_PKG_CACHE = " ${ PKG_MANAGER } update "
PKG_UPDATE = " ${ PKG_MANAGER } upgrade "
PKG_INSTALL = " ${ PKG_MANAGER } --yes --fix-missing install "
# 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 "
# #########################################
# fixes for dependancy differences
# Debian 7 doesn't have iproute2 use iproute
${ PKG_MANAGER } install --dry-run iproute2 > /dev/null 2>& 1 && IPROUTE_PKG = "iproute2" || IPROUTE_PKG = "iproute"
# Ubuntu 16.04 LTS php / php5 fix
${ PKG_MANAGER } install --dry-run php5 > /dev/null 2>& 1 && phpVer = "php5" || phpVer = "php"
# #########################################
INSTALLER_DEPS = ( apt-utils whiptail git dhcpcd5)
PIHOLE_DEPS = ( dnsutils bc dnsmasq lighttpd ${ phpVer } -common ${ phpVer } -cgi curl unzip wget sudo netcat cron ${ IPROUTE_PKG } )
LIGHTTPD_USER = "www-data"
LIGHTTPD_GROUP = "www-data"
LIGHTTPD_CFG = "lighttpd.conf.debian"
DNSMASQ_USER = "dnsmasq"
package_check_install( ) {
dpkg-query -W -f= '${Status}' " ${ 1 } " 2>/dev/null | grep -c "ok installed" || ${ PKG_INSTALL } " ${ 1 } "
}
2016-11-02 08:51:38 +01:00
elif [ $( command -v rpm) ] ; then
2016-11-02 13:17:28 +01:00
# Fedora Family
if [ $( command -v dnf) ] ; then
PKG_MANAGER = "dnf"
else
PKG_MANAGER = "yum"
fi
PKG_CACHE = " /var/cache/ ${ PKG_MANAGER } "
UPDATE_PKG_CACHE = " ${ PKG_MANAGER } check-update "
PKG_UPDATE = " ${ PKG_MANAGER } update -y "
PKG_INSTALL = " ${ PKG_MANAGER } install -y "
PKG_COUNT = " ${ PKG_MANAGER } check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l "
INSTALLER_DEPS = ( iproute net-tools procps-ng newt git )
PIHOLE_DEPS = ( epel-release bind-utils bc dnsmasq lighttpd lighttpd-fastcgi php-common php-cli php curl unzip wget findutils cronie sudo nmap-ncat )
if grep -q 'Fedora' /etc/redhat-release; then
remove_deps = ( epel-release) ;
PIHOLE_DEPS = ( ${ PIHOLE_DEPS [@]/ $remove_deps } ) ;
fi
LIGHTTPD_USER = "lighttpd"
LIGHTTPD_GROUP = "lighttpd"
LIGHTTPD_CFG = "lighttpd.conf.fedora"
DNSMASQ_USER = "nobody"
package_check_install( ) {
rpm -qa | grep ^" ${ 1 } " - > /dev/null || ${ PKG_INSTALL } " ${ 1 } "
}
2016-04-26 06:51:00 +02:00
else
2016-11-02 13:17:28 +01:00
echo "OS distribution not supported"
exit
2016-04-26 06:51:00 +02:00
fi
2015-11-09 00:21:02 +01:00
2016-01-21 18:29:44 +01:00
####### FUNCTIONS ##########
2016-10-20 04:47:45 +02:00
spinner( ) {
2016-11-02 13:17:28 +01:00
local pid = $1
local delay = 0.50
local spinstr = '/-\|'
while [ " $( ps a | awk '{print $1}' | grep " ${ pid } " ) " ] ; do
local temp = ${ spinstr #? }
printf " [%c] " " ${ spinstr } "
local spinstr = ${ temp } ${ spinstr % " $temp " }
sleep ${ delay }
printf "\b\b\b\b\b\b"
done
printf " \b\b\b\b"
2016-01-27 07:11:38 +01:00
}
2016-01-24 04:31:12 +01:00
2016-11-02 08:14:25 +01:00
is_repo( ) {
2016-11-02 14:34:57 +01:00
# Use git to check if directory is currently under VCS, return the value
local directory = " ${ 1 } "
git -C " ${ directory } " status --short & > /dev/null
return
2016-11-02 08:14:25 +01:00
}
make_repo( ) {
2016-11-02 14:34:57 +01:00
local directory = " ${ 1 } "
local remoteRepo = " ${ 2 } "
2016-11-02 08:14:25 +01:00
# Remove the non-repod interface and clone the interface
2016-11-02 14:34:57 +01:00
echo -n " ::: Cloning $remoteRepo into $directory ... "
rm -rf " ${ directory } "
git clone -q --depth 1 " ${ remoteRepo } " " ${ directory } " > /dev/null & spinner $!
2016-11-02 08:14:25 +01:00
echo " done!"
}
update_repo( ) {
2016-11-02 14:34:57 +01:00
local directory = " ${ 1 } "
2016-11-02 08:14:25 +01:00
# Pull the latest commits
echo -n " ::: Updating repo in $1 ... "
2016-11-02 14:34:57 +01:00
cd " ${ directory } " || exit 1
2016-11-02 08:14:25 +01:00
git stash -q > /dev/null & spinner $!
git pull -q > /dev/null & spinner $!
echo " done!"
}
getGitFiles( ) {
# Setup git repos for directory and repository passed
# as arguments 1 and 2
2016-11-02 14:34:57 +01:00
local directory = " ${ 1 } "
local remoteRepo = " ${ 2 } "
2016-11-02 08:14:25 +01:00
echo ":::"
echo "::: Checking for existing repository..."
2016-11-02 14:34:57 +01:00
if is_repo " ${ directory } " ; then
update_repo " ${ directory } "
2016-11-02 08:14:25 +01:00
else
2016-11-02 14:34:57 +01:00
make_repo " ${ directory } " " ${ remoteRepo } "
2016-11-02 08:14:25 +01:00
fi
}
2016-10-10 14:45:37 +02:00
find_IPv4_information( ) {
2016-05-01 04:27:38 +02:00
# Find IP used to route to outside world
IPv4dev = $( ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++)if($i~/dev/)print $(i+1)}' )
2016-11-01 10:45:22 +01:00
IPV4_ADDRESS = $( ip -o -f inet addr show dev " $IPv4dev " | awk '{print $4}' | awk 'END {print}' )
2016-05-01 04:27:38 +02:00
IPv4gw = $( ip route get 8.8.8.8 | awk '{print $3}' )
}
2016-10-10 12:16:22 +02:00
get_available_interfaces( ) {
2016-10-22 08:57:47 +02:00
# Get available interfaces. Consider only getting UP interfaces in the future, and leaving DOWN interfaces out of list.
2016-10-10 12:16:22 +02:00
availableInterfaces = $( ip -o link | awk '{print $2}' | grep -v "lo" | cut -d':' -f1 | cut -d'@' -f1)
}
2015-11-10 01:33:32 +01:00
2016-01-27 07:11:38 +01:00
welcomeDialogs( ) {
2016-04-04 00:25:48 +02:00
# Display the welcome dialog
2016-10-10 14:45:37 +02: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 10:25:00 +01:00
2016-04-04 00:25:48 +02:00
# Support for a part-time dev
2016-10-10 14:45:37 +02: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 10:25:00 +01:00
2016-04-04 00:25:48 +02:00
# Explain the need for a static address
2016-10-10 14:45:37 +02: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-11 00:47:27 +02:00
2016-08-19 23:31:11 +02:00
In the next section, you can choose to use your current network settings ( DHCP) or to manually edit them." ${ r } ${ c }
2015-11-09 00:21:02 +01:00
}
2016-02-10 16:34:06 +01:00
verifyFreeDiskSpace( ) {
2016-08-12 13:44:45 +02:00
2016-04-04 00:25:48 +02:00
# 50MB is the minimum space needed (45MB install (includes web admin bootstrap/jquery libraries etc) + 5MB one day of logs.)
2016-08-12 13:44:45 +02:00
# - Fourdee: Local ensures the variable is only created, and accessible within this function/void. Generally considered a "good" coding practice for non-global variables.
2016-10-02 12:09:14 +02:00
echo "::: Verifying free disk space..."
2016-08-25 13:11:54 +02:00
local required_free_kilobytes = 51200
local existing_free_kilobytes = $( df -Pk | grep -m1 '\/$' | awk '{print $4}' )
2016-04-04 00:25:48 +02:00
2016-08-12 13:44:45 +02:00
# - Unknown free disk space , not a integer
2016-10-22 08:57:47 +02:00
if ! [ [ " ${ existing_free_kilobytes } " = ~ ^( [ 0-9] ) +$ ] ] ; then
echo "::: Unknown free disk space!"
echo "::: We were unable to determine available free disk space on this system."
echo "::: You may override this check and force the installation, however, it is not recommended"
echo "::: To do so, pass the argument '--i_do_not_follow_recommendations' to the install script"
echo "::: eg. curl -L https://install.pi-hole.net | bash /dev/stdin --i_do_not_follow_recommendations"
exit 1
2016-08-12 13:44:45 +02:00
# - Insufficient free disk space
2016-10-02 11:39:09 +02:00
elif [ [ ${ existing_free_kilobytes } -lt ${ required_free_kilobytes } ] ] ; then
2016-10-22 08:57:47 +02:00
echo "::: Insufficient Disk Space!"
echo " ::: Your system appears to be low on disk space. pi-hole recommends a minimum of $required_free_kilobytes KiloBytes. "
echo " ::: You only have ${ existing_free_kilobytes } KiloBytes free. "
echo "::: If this is a new install you may need to expand your disk."
echo "::: Try running 'sudo raspi-config', and choose the 'expand file system option'"
echo "::: After rebooting, run this installation again. (curl -L https://install.pi-hole.net | bash)"
2016-08-12 13:44:45 +02:00
2016-04-04 00:25:48 +02:00
echo "Insufficient free space, exiting..."
exit 1
2016-08-12 13:44:45 +02:00
2016-04-04 00:25:48 +02:00
fi
2016-08-12 13:44:45 +02:00
2016-02-10 16:34:06 +01:00
}
2016-01-27 07:11:38 +01:00
chooseInterface( ) {
2016-04-04 00:25:48 +02:00
# Turn the available interfaces into an array so it can be used with a whiptail dialog
2016-10-10 12:56:03 +02:00
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
2016-04-04 00:25:48 +02:00
2016-10-22 08:57:47 +02:00
while read -r line; do
2016-04-04 00:25:48 +02:00
mode = "OFF"
2016-08-19 23:31:11 +02:00
if [ [ ${ firstLoop } -eq 1 ] ] ; then
firstLoop = 0
2016-04-04 00:25:48 +02:00
mode = "ON"
fi
2016-10-22 08:57:47 +02:00
interfacesArray += ( " ${ line } " "available" " ${ mode } " )
done <<< " ${ availableInterfaces } "
2016-04-04 00:25:48 +02:00
# Find out how many interfaces are available to choose from
2016-10-22 08:57:47 +02:00
interfaceCount = $( echo " ${ availableInterfaces } " | wc -l)
2016-09-19 23:17:58 +02:00
chooseInterfaceCmd = ( whiptail --separate-output --radiolist "Choose An Interface (press space to select)" ${ r } ${ c } ${ interfaceCount } )
2016-04-04 00:25:48 +02:00
chooseInterfaceOptions = $( " ${ chooseInterfaceCmd [@] } " " ${ interfacesArray [@] } " 2>& 1 >/dev/tty)
if [ [ $? = 0 ] ] ; then
2016-10-22 08:57:47 +02:00
for desiredInterface in ${ chooseInterfaceOptions } ; do
2016-11-01 10:45:22 +01:00
PIHOLE_INTERFACE = ${ desiredInterface }
echo " ::: Using interface: $PIHOLE_INTERFACE "
2016-04-04 00:25:48 +02:00
done
else
echo "::: Cancel selected, exiting...."
exit 1
fi
2016-10-10 14:45:37 +02:00
}
2016-03-06 06:16:23 +01:00
2016-10-10 14:45:37 +02:00
useIPv6dialog( ) {
# Show the IPv6 address used for blocking
2016-11-01 10:45:22 +01:00
IPV6_ADDRESS = $( ip -6 route get 2001:4860:4860::8888 | awk -F " " '{ for(i=1;i<=NF;i++) if ($i == "src") print $(i+1) }' )
whiptail --msgbox --backtitle "IPv6..." --title "IPv6 Supported" " $IPV6_ADDRESS will be used to block ads. " ${ r } ${ c }
2015-11-10 01:33:32 +01:00
}
2016-10-10 14:45:37 +02:00
2016-01-27 07:11:38 +01:00
use4andor6( ) {
2016-10-10 14:45:37 +02:00
local useIPv4
local useIPv6
2016-04-04 00:25:48 +02:00
# Let use select IPv4 and/or IPv6
2016-08-19 23:31:11 +02:00
cmd = ( whiptail --separate-output --checklist "Select Protocols (press space to select)" ${ r } ${ c } 2)
2016-04-04 00:25:48 +02:00
options = ( IPv4 "Block ads over IPv4" on
IPv6 "Block ads over IPv6" off)
choices = $( " ${ cmd [@] } " " ${ options [@] } " 2>& 1 >/dev/tty)
if [ [ $? = 0 ] ] ; then
2016-08-19 23:31:11 +02:00
for choice in ${ choices }
2016-04-04 00:25:48 +02:00
do
2016-08-19 23:31:11 +02:00
case ${ choice } in
2016-04-04 00:25:48 +02:00
IPv4 ) useIPv4 = true; ;
IPv6 ) useIPv6 = true; ;
esac
done
2016-10-10 14:45:37 +02:00
if [ [ ${ useIPv4 } ] ] ; then
2016-10-22 08:57:47 +02:00
find_IPv4_information
getStaticIPv4Settings
setStaticIPv4
2016-04-04 00:25:48 +02:00
fi
2016-10-10 14:45:37 +02:00
if [ [ ${ useIPv6 } ] ] ; then
2016-10-22 08:57:47 +02:00
useIPv6dialog
fi
2016-11-01 10:45:22 +01:00
echo " ::: IPv4 address: ${ IPV4_ADDRESS } "
echo " ::: IPv6 address: ${ IPV6_ADDRESS } "
2016-08-19 23:31:11 +02:00
if [ ! ${ useIPv4 } ] && [ ! ${ useIPv6 } ] ; then
2016-04-04 00:25:48 +02:00
echo "::: Cannot continue, neither IPv4 or IPv6 selected"
echo "::: Exiting"
exit 1
fi
else
echo "::: Cancel selected. Exiting..."
exit 1
fi
2015-11-10 01:33:32 +01:00
}
2015-11-09 00:21:02 +01:00
2016-01-27 07:11:38 +01:00
getStaticIPv4Settings( ) {
2016-04-04 00:25:48 +02:00
# Ask if the user wants to use DHCP settings as their static IP
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-11-01 10:45:22 +01:00
IP address: ${ IPV4_ADDRESS }
2016-10-22 08:57:47 +02:00
Gateway: ${ IPv4gw } " ${ r } ${ c } ); then
2016-04-04 00:25:48 +02: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-04 01:05:11 +02: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 23:31:11 +02: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 }
2016-04-04 00:25:48 +02:00
# Nothing else to do since the variables are already set above
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
2016-10-22 08:57:47 +02:00
until [ [ ${ ipSettingsCorrect } = True ] ] ; do
2016-04-04 00:25:48 +02:00
# Ask for the IPv4 address
2016-11-01 10:45:22 +01: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)
2016-10-22 08:57:47 +02:00
if [ [ $? = 0 ] ] ; then
2016-11-01 10:45:22 +01:00
echo " ::: Your static IPv4 address: ${ IPV4_ADDRESS } "
2016-04-04 00:25:48 +02:00
# Ask for the gateway
2016-10-22 08:57:47 +02: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)
if [ [ $? = 0 ] ] ; then
echo " ::: Your static IPv4 gateway: ${ IPv4gw } "
2016-04-04 00:25:48 +02:00
# Give the user a chance to review their settings before moving on
if ( whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno " Are these settings correct?
2016-11-01 10:45:22 +01:00
IP address: ${ IPV4_ADDRESS }
2016-10-22 08:57:47 +02:00
Gateway: ${ IPv4gw } " ${ r } ${ c } ); then
2016-04-04 00:25:48 +02:00
# After that's done, the loop ends and we move on
ipSettingsCorrect = True
else
# If the settings are wrong, the loop continues
ipSettingsCorrect = False
fi
else
# Cancelling gateway settings window
ipSettingsCorrect = False
echo "::: Cancel selected. Exiting..."
exit 1
fi
else
# Cancelling IPv4 settings window
ipSettingsCorrect = False
echo "::: Cancel selected. Exiting..."
exit 1
fi
done
# End the if statement for DHCP vs. static
fi
2015-11-09 00:21:02 +01:00
}
2016-01-27 07:11:38 +01:00
setDHCPCD( ) {
2016-04-04 00:25:48 +02:00
# Append these lines to dhcpcd.conf to enable a static IP
2016-11-01 10:45:22 +01:00
echo " ## interface ${ PIHOLE_INTERFACE }
static ip_address = ${ IPV4_ADDRESS }
2016-10-22 08:57:47 +02:00
static routers = ${ IPv4gw }
static domain_name_servers = ${ IPv4gw } " | tee -a /etc/dhcpcd.conf >/dev/null
2015-10-31 15:11:29 +01:00
}
2016-01-27 07:11:38 +01:00
setStaticIPv4( ) {
2016-10-22 08:57:47 +02:00
local IFCFG_FILE
local IPADDR
local CIDR
if [ [ -f /etc/dhcpcd.conf ] ] ; then
2016-06-12 06:08:18 +02:00
# Debian Family
2016-11-01 10:45:22 +01:00
if grep -q " ${ IPV4_ADDRESS } " /etc/dhcpcd.conf; then
2016-06-12 06:08:18 +02:00
echo "::: Static IP already configured"
else
setDHCPCD
2016-11-01 10:45:22 +01:00
ip addr replace dev " ${ PIHOLE_INTERFACE } " " ${ IPV4_ADDRESS } "
2016-06-12 06:08:18 +02:00
echo ":::"
2016-11-01 10:45:22 +01:00
echo " ::: Setting IP to ${ IPV4_ADDRESS } . You may need to restart after the install is complete. "
2016-06-12 06:08:18 +02:00
echo ":::"
fi
2016-11-01 10:45:22 +01:00
elif [ [ -f /etc/sysconfig/network-scripts/ifcfg-${ PIHOLE_INTERFACE } ] ] ; then
2016-06-12 06:08:18 +02:00
# Fedora Family
2016-11-01 10:45:22 +01:00
IFCFG_FILE = /etc/sysconfig/network-scripts/ifcfg-${ PIHOLE_INTERFACE }
if grep -q " ${ IPV4_ADDRESS } " " ${ IFCFG_FILE } " ; then
2016-06-12 06:08:18 +02:00
echo "::: Static IP already configured"
else
2016-11-01 10:45:22 +01:00
IPADDR = $( echo " ${ IPV4_ADDRESS } " | cut -f1 -d/)
CIDR = $( echo " ${ IPV4_ADDRESS } " | cut -f2 -d/)
2016-06-12 06:08:18 +02:00
# Backup existing interface configuration:
2016-10-16 23:11:47 +02:00
cp " ${ IFCFG_FILE } " " ${ IFCFG_FILE } " .pihole.orig
2016-06-12 06:08:18 +02:00
# Build Interface configuration file:
2016-10-10 11:57:04 +02:00
{
2016-10-22 08:57:47 +02:00
echo "# Configured via Pi-Hole installer"
2016-11-01 10:45:22 +01:00
echo " DEVICE= $PIHOLE_INTERFACE "
2016-10-22 08:57:47 +02:00
echo "BOOTPROTO=none"
echo "ONBOOT=yes"
echo " IPADDR= $IPADDR "
echo " PREFIX= $CIDR "
echo " GATEWAY= $IPv4gw "
2016-11-01 10:45:22 +01:00
echo " DNS1= $PIHOLE_DNS_1 "
echo " DNS2= $PIHOLE_DNS_2 "
2016-10-22 08:57:47 +02:00
echo "USERCTL=no"
2016-10-10 11:57:04 +02:00
} >> " ${ IFCFG_FILE } "
2016-11-01 10:45:22 +01:00
ip addr replace dev " ${ PIHOLE_INTERFACE } " " ${ IPV4_ADDRESS } "
2016-06-12 06:08:18 +02:00
if [ -x " $( command -v nmcli) " ] ; then
# Tell NetworkManager to read our new sysconfig file
2016-10-10 11:57:04 +02:00
nmcli con load " ${ IFCFG_FILE } " > /dev/null
2016-06-12 06:08:18 +02:00
fi
echo ":::"
2016-11-01 10:45:22 +01:00
echo " ::: Setting IP to ${ IPV4_ADDRESS } . You may need to restart after the install is complete. "
2016-06-12 06:08:18 +02:00
echo ":::"
fi
2016-04-04 00:25:48 +02:00
else
2016-06-12 06:08:18 +02:00
echo "::: Warning: Unable to locate configuration file to set static IPv4 address!"
exit 1
2016-04-04 00:25:48 +02:00
fi
2015-12-06 11:40:30 +01:00
}
2016-10-20 04:47:45 +02:00
valid_ip( ) {
2016-10-22 08:57:47 +02:00
local ip = ${ 1 }
local stat = 1
2016-04-04 00:25:48 +02:00
2016-08-19 23:31:11 +02:00
if [ [ ${ ip } = ~ ^[ 0-9] { 1,3} \. [ 0-9] { 1,3} \. [ 0-9] { 1,3} \. [ 0-9] { 1,3} $ ] ] ; then
2016-04-04 00:25:48 +02:00
OIFS = $IFS
IFS = '.'
2016-08-19 23:31:11 +02:00
ip = ( ${ ip } )
IFS = ${ OIFS }
2016-04-04 00:25:48 +02:00
[ [ ${ ip [0] } -le 255 && ${ ip [1] } -le 255 \
&& ${ ip [2] } -le 255 && ${ ip [3] } -le 255 ] ]
stat = $?
fi
2016-08-19 23:31:11 +02:00
return ${ stat }
2016-02-20 18:33:20 +01:00
}
2016-10-20 04:47:45 +02:00
setDNS( ) {
2016-10-10 23:34:12 +02:00
DNSChooseCmd = ( whiptail --separate-output --radiolist "Select Upstream DNS Provider. To use your own, select Custom." ${ r } ${ c } 6)
2016-04-04 00:25:48 +02:00
DNSChooseOptions = ( Google "" on
OpenDNS "" off
Level3 "" off
Norton "" off
Comodo "" off
Custom "" off)
2016-10-10 23:34:12 +02:00
DNSchoices = $( " ${ DNSChooseCmd [@] } " " ${ DNSChooseOptions [@] } " 2>& 1 >/dev/tty)
2016-04-04 00:25:48 +02:00
if [ [ $? = 0 ] ] ; then
2016-08-19 23:31:11 +02:00
case ${ DNSchoices } in
2016-10-22 08:57:47 +02:00
Google)
echo "::: Using Google DNS servers."
2016-11-01 10:45:22 +01:00
PIHOLE_DNS_1 = "8.8.8.8"
PIHOLE_DNS_2 = "8.8.4.4"
2016-10-22 08:57:47 +02:00
; ;
OpenDNS)
echo "::: Using OpenDNS servers."
2016-11-01 10:45:22 +01:00
PIHOLE_DNS_1 = "208.67.222.222"
PIHOLE_DNS_2 = "208.67.220.220"
2016-10-22 08:57:47 +02:00
; ;
Level3)
echo "::: Using Level3 servers."
2016-11-01 10:45:22 +01:00
PIHOLE_DNS_1 = "4.2.2.1"
PIHOLE_DNS_2 = "4.2.2.2"
2016-10-22 08:57:47 +02:00
; ;
Norton)
echo "::: Using Norton ConnectSafe servers."
2016-11-01 10:45:22 +01:00
PIHOLE_DNS_1 = "199.85.126.10"
PIHOLE_DNS_2 = "199.85.127.10"
2016-10-22 08:57:47 +02:00
; ;
Comodo)
echo "::: Using Comodo Secure servers."
2016-11-01 10:45:22 +01:00
PIHOLE_DNS_1 = "8.26.56.26"
PIHOLE_DNS_2 = "8.20.247.20"
2016-10-22 08:57:47 +02:00
; ;
Custom)
until [ [ ${ DNSSettingsCorrect } = True ] ] ; do
strInvalid = "Invalid"
2016-11-01 10:45:22 +01:00
if [ ! ${ PIHOLE_DNS_1 } ] ; then
if [ ! ${ PIHOLE_DNS_2 } ] ; then
2016-10-22 08:57:47 +02:00
prePopulate = ""
else
2016-11-01 10:45:22 +01:00
prePopulate = " , ${ PIHOLE_DNS_2 } "
2016-10-22 08:57:47 +02:00
fi
2016-11-01 10:45:22 +01:00
elif [ ${ PIHOLE_DNS_1 } ] && [ ! ${ PIHOLE_DNS_2 } ] ; then
prePopulate = " ${ PIHOLE_DNS_1 } "
elif [ ${ PIHOLE_DNS_1 } ] && [ ${ PIHOLE_DNS_2 } ] ; then
prePopulate = " ${ PIHOLE_DNS_1 } , ${ PIHOLE_DNS_2 } "
2016-10-22 08:57:47 +02:00
fi
piholeDNS = $( whiptail --backtitle "Specify Upstream DNS Provider(s)" --inputbox "Enter your desired upstream DNS provider(s), seperated by a comma.\n\nFor example '8.8.8.8, 8.8.4.4'" ${ r } ${ c } " ${ prePopulate } " 3>& 1 1>& 2 2>& 3)
if [ [ $? = 0 ] ] ; then
2016-11-01 10:45:22 +01: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}' )
if ! valid_ip " ${ PIHOLE_DNS_1 } " || [ ! " ${ PIHOLE_DNS_1 } " ] ; then
PIHOLE_DNS_1 = ${ strInvalid }
2016-10-22 08:57:47 +02:00
fi
2016-11-01 10:45:22 +01:00
if ! valid_ip " ${ PIHOLE_DNS_2 } " && [ " ${ PIHOLE_DNS_2 } " ] ; then
PIHOLE_DNS_2 = ${ strInvalid }
2016-10-22 08:57:47 +02:00
fi
else
echo "::: Cancel selected, exiting...."
exit 1
fi
2016-11-01 10:45:22 +01:00
if [ [ ${ PIHOLE_DNS_1 } = = " ${ strInvalid } " ] ] || [ [ ${ PIHOLE_DNS_2 } = = " ${ strInvalid } " ] ] ; then
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 }
if [ [ ${ PIHOLE_DNS_1 } = = " ${ strInvalid } " ] ] ; then
PIHOLE_DNS_1 = ""
2016-10-22 08:57:47 +02:00
fi
2016-11-01 10:45:22 +01:00
if [ [ ${ PIHOLE_DNS_2 } = = " ${ strInvalid } " ] ] ; then
PIHOLE_DNS_2 = ""
2016-10-22 08:57:47 +02:00
fi
DNSSettingsCorrect = False
else
2016-11-01 10:45:22 +01: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
2016-10-22 08:57:47 +02:00
DNSSettingsCorrect = True
else
# If the settings are wrong, the loop continues
DNSSettingsCorrect = False
fi
fi
done
; ;
esac
2016-04-04 00:25:48 +02:00
else
echo "::: Cancel selected. Exiting..."
exit 1
fi
2016-01-25 06:11:00 +01:00
}
2016-10-31 22:38:48 +01:00
setLogging( ) {
2016-11-01 00:48:58 +01:00
local LogToggleCommand
local LogChooseOptions
local LogChoices
2016-10-31 22:40:20 +01: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)
2016-11-01 00:48:02 +01:00
LogChooseOptions = ( "On (Reccomended)" "" on
2016-10-31 22:38:48 +01:00
Off "" off)
2016-11-01 00:55:10 +01:00
LogChoices = $( " ${ LogToggleCommand [@] } " " ${ LogChooseOptions [@] } " 2>& 1 >/dev/tty) || ( echo "::: Cancel selected. Exiting..." && exit 1)
2016-11-01 00:48:02 +01:00
case ${ LogChoices } in
2016-10-31 22:40:20 +01:00
"On (Recommended)" )
2016-10-31 22:38:48 +01:00
echo "::: Logging On."
2016-11-01 10:33:39 +01:00
QUERY_LOGGING = true
2016-10-31 22:38:48 +01:00
; ;
Off)
echo "::: Logging Off."
2016-11-01 10:33:39 +01:00
QUERY_LOGGING = false
2016-10-31 22:38:48 +01:00
; ;
esac
}
2016-10-20 04:47:45 +02:00
version_check_dnsmasq( ) {
2016-04-04 00:25:48 +02:00
# Check if /etc/dnsmasq.conf is from pihole. If so replace with an original and install new in .d directory
2016-10-10 12:23:52 +02: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"
local dnsmasq_original_config = "/etc/.pihole/advanced/dnsmasq.conf.original"
local dnsmasq_pihole_01_snippet = "/etc/.pihole/advanced/01-pihole.conf"
local dnsmasq_pihole_01_location = "/etc/dnsmasq.d/01-pihole.conf"
if [ -f ${ dnsmasq_conf } ] ; then
2016-04-04 00:25:48 +02:00
echo -n "::: Existing dnsmasq.conf found..."
2016-10-10 12:23:52 +02:00
if grep -q ${ dnsmasq_pihole_id_string } ${ dnsmasq_conf } ; then
2016-04-04 00:25:48 +02:00
echo " it is from a previous pi-hole install."
echo -n "::: Backing up dnsmasq.conf to dnsmasq.conf.orig..."
2016-10-10 12:23:52 +02:00
mv -f ${ dnsmasq_conf } ${ dnsmasq_conf_orig }
2016-04-04 00:25:48 +02:00
echo " done."
echo -n "::: Restoring default dnsmasq.conf..."
2016-10-10 12:23:52 +02:00
cp ${ dnsmasq_original_config } ${ dnsmasq_conf }
2016-04-04 00:25:48 +02:00
echo " done."
else
echo " it is not a pi-hole file, leaving alone!"
fi
else
echo -n "::: No dnsmasq.conf found.. restoring default dnsmasq.conf..."
2016-10-10 12:23:52 +02:00
cp ${ dnsmasq_original_config } ${ dnsmasq_conf }
2016-04-04 00:25:48 +02:00
echo " done."
fi
echo -n "::: Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf..."
2016-10-10 12:23:52 +02:00
cp ${ dnsmasq_pihole_01_snippet } ${ dnsmasq_pihole_01_location }
2016-04-04 00:25:48 +02:00
echo " done."
2016-11-01 10:45:22 +01:00
sed -i " s/@INT@/ $PIHOLE_INTERFACE / " ${ dnsmasq_pihole_01_location }
if [ [ " ${ PIHOLE_DNS_1 } " != "" ] ] ; then
sed -i " s/@DNS1@/ $PIHOLE_DNS_1 / " ${ dnsmasq_pihole_01_location }
2016-04-04 00:25:48 +02:00
else
2016-10-10 12:23:52 +02:00
sed -i '/^server=@DNS1@/d' ${ dnsmasq_pihole_01_location }
2016-04-04 00:25:48 +02:00
fi
2016-11-01 10:45:22 +01:00
if [ [ " ${ PIHOLE_DNS_2 } " != "" ] ] ; then
sed -i " s/@DNS2@/ $PIHOLE_DNS_2 / " ${ dnsmasq_pihole_01_location }
2016-04-04 00:25:48 +02:00
else
2016-10-10 12:23:52 +02:00
sed -i '/^server=@DNS2@/d' ${ dnsmasq_pihole_01_location }
2016-04-04 00:25:48 +02:00
fi
2016-10-25 16:06:37 +02:00
2016-10-25 16:27:13 +02:00
#sed -i "s/@HOSTNAME@/$hostname/" ${dnsmasq_pihole_01_location}
2016-10-25 16:06:37 +02:00
if [ [ -f /etc/hostname ] ] ; then
hostname = $( </etc/hostname)
elif [ -x " $( command -v hostname) " ] ; then
hostname = $( hostname -f)
2016-10-25 16:27:13 +02:00
fi
#Replace IPv4 and IPv6 tokens in 01-pihole.conf for pi.hole resolution.
2016-11-01 10:45:22 +01:00
if [ [ " ${ IPV4_ADDRESS } " != "" ] ] ; then
tmp = ${ IPV4_ADDRESS %/* }
2016-10-25 16:27:13 +02:00
sed -i " s/@IPv4@/ $tmp / " ${ dnsmasq_pihole_01_location }
2016-10-25 16:06:37 +02:00
else
2016-10-27 12:13:00 +02:00
sed -i '/^address=\/pi.hole\/@IPv4@/d' ${ dnsmasq_pihole_01_location }
sed -i '/^address=\/@HOSTNAME@\/@IPv4@/d' ${ dnsmasq_pihole_01_location }
2016-10-25 16:27:13 +02:00
fi
2016-11-01 10:45:22 +01:00
if [ [ " ${ IPV6_ADDRESS } " != "" ] ] ; then
sed -i " s/@IPv6@/ $IPV6_ADDRESS / " ${ dnsmasq_pihole_01_location }
2016-10-25 16:27:13 +02:00
else
2016-10-27 12:13:00 +02:00
sed -i '/^address=\/pi.hole\/@IPv6@/d' ${ dnsmasq_pihole_01_location }
sed -i '/^address=\/@HOSTNAME@\/@IPv6@/d' ${ dnsmasq_pihole_01_location }
2016-10-25 16:06:37 +02:00
fi
2016-10-25 16:27:13 +02:00
if [ [ " ${ hostname } " != "" ] ] ; then
sed -i " s/@HOSTNAME@/ $hostname / " ${ dnsmasq_pihole_01_location }
else
2016-10-27 12:13:00 +02:00
sed -i '/^address=\/@HOSTNAME@*/d' ${ dnsmasq_pihole_01_location }
2016-10-25 16:27:13 +02:00
fi
2016-10-25 16:00:18 +02:00
2016-10-10 12:23:52 +02:00
sed -i 's/^#conf-dir=\/etc\/dnsmasq.d$/conf-dir=\/etc\/dnsmasq.d/' ${ dnsmasq_conf }
2016-10-31 22:38:48 +01:00
2016-11-01 10:33:39 +01:00
if [ [ " ${ QUERY_LOGGING } " = = false ] ] ; then
2016-10-31 22:38:48 +01:00
#Disable Logging
sed -i 's/^log-queries/#log-queries/' ${ dnsmasq_pihole_01_location }
else
#Enable Logging
sed -i 's/^#log-queries/log-queries/' ${ dnsmasq_pihole_01_location }
fi
2016-01-25 06:04:02 +01:00
}
2016-10-20 04:47:45 +02:00
remove_legacy_scripts( ) {
2016-10-10 10:43:10 +02:00
#Tidy up /usr/local/bin directory if installing over previous install.
oldFiles = ( gravity chronometer whitelist blacklist piholeLogFlush updateDashboard uninstall setupLCD piholeDebug)
for i in " ${ oldFiles [@] } " ; do
if [ -f " /usr/local/bin/ $i .sh " ] ; then
rm /usr/local/bin/" $i " .sh
fi
done
}
2016-11-02 08:14:25 +01:00
clean_existing( ) {
# Clean an exiting installation to prepare for upgrade/reinstall
# ${1} Directory to clean; ${2} Array of files to remove
local clean_directory = " ${ 1 } "
local old_files = ${ 2 }
for script in " ${ old_files [@] } " ; do
rm -f " ${ clean_directory } ${ script } .sh "
done
2016-10-05 18:57:48 +02:00
2016-11-02 08:14:25 +01:00
}
2016-10-05 18:57:48 +02:00
2016-11-02 08:14:25 +01:00
installScripts( ) {
# Install the scripts from repository to their various locations
readonly install_dir = "/opt/pihole/"
2016-10-05 19:19:47 +02:00
2016-11-02 08:14:25 +01:00
echo ":::"
2016-11-02 14:34:57 +01:00
echo -n " ::: Installing scripts from ${ PI_HOLE_LOCAL_REPO } ... "
2016-11-02 08:14:25 +01:00
# Clear out script files from Pi-hole scripts directory.
clean_existing " ${ install_dir } " " ${ PI_HOLE_FILES } "
# Install files from local core repository
2016-11-02 14:34:57 +01:00
if is_repo " ${ PI_HOLE_LOCAL_REPO } " ; then
2016-11-02 08:14:25 +01:00
cd " ${ PI_HOLE_LOCAL_REPO } "
install -o " ${ USER } " -Dm755 -t /opt/pihole/ gravity.sh
install -o " ${ USER } " -Dm755 -t /opt/pihole/ ./advanced/Scripts/*.sh
install -o " ${ USER } " -Dm755 -t /opt/pihole/ ./automated\ install/uninstall.sh
install -o " ${ USER } " -Dm755 -t /usr/local/bin/ pihole
install -Dm644 ./advanced/bash-completion/pihole /etc/bash_completion.d/pihole
echo " done."
else
echo " *** ERROR: Local repo ${ core_repo } not found, exiting. "
exit 1
fi
2015-12-03 18:25:13 +01:00
}
2016-01-27 07:11:38 +01:00
installConfigs( ) {
2016-04-04 00:25:48 +02:00
# Install the configs from /etc/.pihole to their various locations
2016-10-05 19:46:10 +02:00
echo ":::"
echo "::: Installing configs..."
2016-10-10 12:23:52 +02:00
version_check_dnsmasq
2016-04-04 00:25:48 +02:00
if [ ! -d "/etc/lighttpd" ] ; then
2016-10-08 21:56:26 +02:00
mkdir /etc/lighttpd
2016-10-22 08:57:47 +02:00
chown " ${ USER } " :root /etc/lighttpd
2016-10-08 21:56:26 +02:00
mv /etc/lighttpd/lighttpd.conf /etc/lighttpd/lighttpd.conf.orig
2016-04-04 00:25:48 +02:00
fi
2016-10-08 21:56:26 +02:00
cp /etc/.pihole/advanced/${ LIGHTTPD_CFG } /etc/lighttpd/lighttpd.conf
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
2016-10-19 14:27:17 +02:00
mkdir -p /var/cache/lighttpd/uploads
chown ${ LIGHTTPD_USER } :${ LIGHTTPD_GROUP } /var/cache/lighttpd/uploads
2015-12-03 18:25:13 +01:00
}
2016-10-10 10:25:11 +02:00
stop_service( ) {
# Stop service passed in as argument.
# Can softfail, as process may not be installed when this is called
2016-10-05 19:46:10 +02:00
echo ":::"
2016-10-10 10:25:11 +02:00
echo -n " ::: Stopping ${ 1 } service... "
2016-05-01 16:45:41 +02:00
if [ -x " $( command -v systemctl) " ] ; then
2016-10-10 10:25:11 +02:00
systemctl stop " ${ 1 } " & > /dev/null & spinner $! || true
2016-05-01 16:45:41 +02:00
else
2016-10-10 15:06:34 +02:00
service " ${ 1 } " stop & > /dev/null & spinner $! || true
fi
echo " done."
}
start_service( ) {
2016-10-22 08:57:47 +02:00
# Start/Restart service passed in as argument
# This should not fail, it's an error if it does
2016-10-10 15:06:34 +02:00
echo ":::"
echo -n " ::: Starting ${ 1 } service... "
if [ -x " $( command -v systemctl) " ] ; then
systemctl restart " ${ 1 } " & > /dev/null & spinner $!
else
service " ${ 1 } " restart & > /dev/null & spinner $!
fi
echo " done."
}
enable_service( ) {
2016-10-22 08:57:47 +02:00
# Enable service so that it will start with next reboot
2016-10-10 15:06:34 +02:00
echo ":::"
echo -n " ::: Enabling ${ 1 } service to start on reboot... "
if [ -x " $( command -v systemctl) " ] ; then
systemctl enable " ${ 1 } " & > /dev/null & spinner $!
else
update-rc.d " ${ 1 } " defaults & > /dev/null & spinner $!
2016-05-01 16:45:41 +02:00
fi
2016-10-05 19:46:10 +02:00
echo " done."
2015-12-03 18:25:13 +01:00
}
2016-10-10 07:05:06 +02:00
2016-10-10 11:24:03 +02:00
update_pacakge_cache( ) {
2016-04-04 00:25:48 +02: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-10-10 11:24:03 +02:00
2016-04-04 00:25:48 +02:00
#Check to see if apt-get update has already been run today
2016-10-10 11:24:03 +02:00
#it needs to have been run at least once on new installs!
2016-08-19 23:31:11 +02:00
timestamp = $( stat -c %Y ${ PKG_CACHE } )
2016-10-22 08:57:47 +02:00
timestampAsDate = $( date -d @" ${ timestamp } " "+%b %e" )
2016-04-04 00:25:48 +02:00
today = $( date "+%b %e" )
2016-10-22 08:57:47 +02:00
if [ ! " ${ today } " = = " ${ timestampAsDate } " ] ; then
2016-04-04 00:25:48 +02:00
#update package lists
echo ":::"
2016-10-22 08:57:47 +02:00
echo -n " ::: ${ PKG_MANAGER } update has not been run today. Running now... "
2016-10-10 16:25:43 +02:00
${ UPDATE_PKG_CACHE } & > /dev/null & spinner $!
2016-04-04 00:25:48 +02:00
echo " done!"
fi
2016-10-10 11:24:03 +02:00
}
2016-10-20 04:47:45 +02:00
notify_package_updates_available( ) {
2016-10-10 11:24:03 +02:00
# Let user know if they have outdated packages on their system and
# advise them to run a package update at soonest possible.
2016-04-04 00:25:48 +02:00
echo ":::"
2016-10-22 08:57:47 +02:00
echo -n " ::: Checking ${ PKG_MANAGER } for upgraded packages.... "
2016-10-08 21:56:26 +02:00
updatesToInstall = $( eval " ${ PKG_COUNT } " )
2016-05-01 08:27:46 +02:00
echo " done!"
2016-05-02 01:46:15 +02:00
echo ":::"
2016-08-19 23:31:11 +02:00
if [ [ ${ updatesToInstall } -eq "0" ] ] ; then
2016-10-10 11:24:03 +02:00
echo "::: Your system is up to date! Continuing with Pi-hole installation..."
2016-05-02 01:46:15 +02:00
else
2016-10-22 08:57:47 +02:00
echo " ::: There are ${ updatesToInstall } updates available for your system! "
echo " ::: We recommend you run ' ${ PKG_UPDATE } ' after installing Pi-Hole! "
2016-04-04 00:25:48 +02:00
echo ":::"
2016-05-02 01:46:15 +02:00
fi
2016-10-10 07:00:23 +02:00
}
2016-10-20 04:47:45 +02:00
install_dependent_packages( ) {
2016-10-22 08:57:47 +02:00
# Install packages passed in via argument array
# No spinner - conflicts with set -e
declare -a argArray1 = ( " ${ !1 } " )
2016-10-10 07:05:06 +02:00
2016-10-10 11:24:03 +02:00
for i in " ${ argArray1 [@] } " ; do
echo -n " ::: Checking for $i ... "
2016-10-10 16:25:43 +02:00
package_check_install " ${ i } " & > /dev/null
2016-10-10 11:24:03 +02:00
echo " installed!"
done
2015-12-03 18:25:13 +01:00
}
2016-01-27 07:11:38 +01:00
CreateLogFile( ) {
2016-04-04 00:25:48 +02:00
# Create logfiles if necessary
echo ":::"
2016-10-22 08:57:47 +02:00
echo -n "::: Creating log file and changing owner to dnsmasq..."
2016-04-04 00:25:48 +02:00
if [ ! -f /var/log/pihole.log ] ; then
2016-10-08 21:56:26 +02:00
touch /var/log/pihole.log
chmod 644 /var/log/pihole.log
2016-10-10 20:05:29 +02:00
chown " ${ DNSMASQ_USER } " :root /var/log/pihole.log
2016-10-08 21:56:26 +02:00
echo " done!"
2016-04-04 00:25:48 +02:00
else
2016-10-08 21:56:26 +02:00
echo " already exists!"
2016-04-04 00:25:48 +02:00
fi
2015-12-03 18:25:13 +01:00
}
2016-01-27 07:11:38 +01:00
installPiholeWeb( ) {
2016-04-04 00:25:48 +02:00
# Install the web interface
2016-10-08 21:56:26 +02:00
echo ":::"
2016-11-02 21:57:56 +01:00
echo "::: Installing pihole custom index page..."
2016-04-04 00:25:48 +02:00
if [ -d "/var/www/html/pihole" ] ; then
2016-11-02 21:57:56 +01:00
if [ -f "/var/www/html/pihole/index.html" ] ; then
echo "::: Existing index.html detected, not overwriting"
else
echo -n "::: index.html missing, replacing... "
cp /etc/.pihole/advanced/index.html /var/www/html/pihole/
echo " done!"
fi
if [ -f "/var/www/html/pihole/index.js" ] ; then
echo "::: Existing index.js detected, not overwriting"
else
2016-11-02 22:17:00 +01:00
echo -n "::: index.js missing, replacing... "
2016-11-02 21:57:56 +01:00
cp /etc/.pihole/advanced/index.js /var/www/html/pihole/
echo " done!"
fi
2016-04-04 00:25:48 +02:00
else
2016-10-08 21:56:26 +02:00
mkdir /var/www/html/pihole
2016-04-04 00:25:48 +02:00
if [ -f /var/www/html/index.lighttpd.html ] ; then
2016-10-08 21:56:26 +02:00
mv /var/www/html/index.lighttpd.html /var/www/html/index.lighttpd.orig
2016-04-04 00:25:48 +02:00
else
printf "\n:::\tNo default index.lighttpd.html file found... not backing up"
fi
2016-10-08 21:56:26 +02:00
cp /etc/.pihole/advanced/index.* /var/www/html/pihole/.
echo " done!"
2016-04-04 00:25:48 +02:00
fi
2016-04-18 05:03:12 +02:00
# Install Sudoer file
2016-11-02 22:06:12 +01:00
echo ":::"
2016-04-18 05:03:12 +02:00
echo -n "::: Installing sudoer file..."
2016-10-08 21:56:26 +02:00
mkdir -p /etc/sudoers.d/
cp /etc/.pihole/advanced/pihole.sudo /etc/sudoers.d/pihole
chmod 0440 /etc/sudoers.d/pihole
2016-04-18 05:03:12 +02:00
echo " done!"
2015-12-03 18:25:13 +01:00
}
2016-01-27 07:11:38 +01:00
installCron( ) {
2016-04-04 00:25:48 +02:00
# Install the cron job
2016-10-08 21:56:26 +02:00
echo ":::"
echo -n "::: Installing latest Cron script..."
cp /etc/.pihole/advanced/pihole.cron /etc/cron.d/pihole
echo " done!"
2015-12-03 18:25:13 +01:00
}
2016-01-27 07:11:38 +01:00
runGravity( ) {
2016-10-10 07:38:00 +02:00
# Run gravity.sh to build blacklists
2016-10-08 21:56:26 +02:00
echo ":::"
echo "::: Preparing to run gravity.sh to refresh hosts..."
2016-04-04 00:25:48 +02:00
if ls /etc/pihole/list* 1> /dev/null 2>& 1; then
echo "::: Cleaning up previous install (preserving whitelist/blacklist)"
2016-10-08 21:56:26 +02:00
rm /etc/pihole/list.*
2016-04-04 00:25:48 +02:00
fi
echo "::: Running gravity.sh"
2016-10-08 21:56:26 +02:00
/opt/pihole/gravity.sh
2016-01-19 23:52:29 +01:00
}
2016-10-20 04:47:45 +02:00
create_pihole_user( ) {
2016-04-04 00:25:48 +02:00
# Check if user pihole exists and create if not
echo "::: Checking if user 'pihole' exists..."
2016-10-10 18:21:28 +02:00
id -u pihole & > /dev/null && echo "::: User 'pihole' already exists" || ( echo "::: User 'pihole' doesn't exist. Creating..." && useradd -r -s /usr/sbin/nologin pihole)
2016-01-25 06:28:53 +01:00
}
2016-01-21 00:34:18 +01:00
2016-05-15 01:05:40 +02:00
configureFirewall( ) {
# Allow HTTP and DNS traffic
if [ -x " $( command -v firewall-cmd) " ] ; then
2016-10-10 20:30:15 +02:00
firewall-cmd --state & > /dev/null && ( echo "::: Configuring firewalld for httpd and dnsmasq.." && firewall-cmd --permanent --add-port= 80/tcp && firewall-cmd --permanent --add-port= 53/tcp \
&& firewall-cmd --permanent --add-port= 53/udp && firewall-cmd --reload) || echo "::: FirewallD not enabled"
2016-05-15 01:05:40 +02:00
elif [ -x " $( command -v iptables) " ] ; then
2016-10-08 21:56:26 +02:00
echo "::: Configuring iptables for httpd and dnsmasq.."
iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 53 -j ACCEPT
iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT
2016-05-15 01:05:40 +02:00
else
2016-10-08 21:56:26 +02:00
echo "::: No firewall detected.. skipping firewall configuration."
2016-05-15 01:05:40 +02:00
fi
}
2016-08-26 23:45:38 +02:00
finalExports( ) {
2016-10-22 08:57:47 +02:00
#If it already exists, lets overwrite it with the new values.
if [ [ -f ${ setupVars } ] ] ; then
rm ${ setupVars }
fi
2016-10-10 11:57:04 +02:00
{
2016-11-01 10:45:22 +01: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 } "
2016-11-01 10:33:39 +01:00
echo " QUERY_LOGGING= ${ QUERY_LOGGING } "
2016-10-10 14:45:37 +02:00
} >> " ${ setupVars } "
2015-11-07 19:07:50 +01:00
}
2016-08-19 23:45:24 +02:00
installPihole( ) {
2016-10-22 08:57:47 +02:00
# Install base files and web interface
create_pihole_user
if [ ! -d "/var/www/html" ] ; then
mkdir -p /var/www/html
fi
chown ${ LIGHTTPD_USER } :${ LIGHTTPD_GROUP } /var/www/html
chmod 775 /var/www/html
usermod -a -G ${ LIGHTTPD_GROUP } pihole
if [ -x " $( command -v lighty-enable-mod) " ] ; then
lighty-enable-mod fastcgi fastcgi-php > /dev/null || true
else
printf "\n:::\tWarning: 'lighty-enable-mod' utility not found. Please ensure fastcgi is enabled if you experience issues.\n"
fi
installScripts
installConfigs
CreateLogFile
configureSelinux
installPiholeWeb
installCron
configureFirewall
finalExports
runGravity
2016-08-19 23:45:24 +02:00
}
2016-11-01 10:36:59 +01:00
accountForRefactor( ) {
# At some point in the future this list can be pruned, for now we'll need it to ensure updates don't break.
2016-11-01 10:45:22 +01:00
2016-10-22 08:57:47 +02:00
# Refactoring of install script has changed the name of a couple of variables. Sort them out here.
sed -i 's/IPv4addr/IPv4_address/g' ${ setupVars }
sed -i 's/piholeIPv6/IPv6_address/g' ${ setupVars }
2016-11-01 10:36:59 +01:00
2016-11-01 10:45:22 +01:00
# Account for renaming of global variables.
sed -i 's/piholeInterface/PIHOLE_INTERFACE/g' ${ setupVars }
sed -i 's/IPv4_address/IPV4_ADDRESS/g' ${ setupVars }
sed -i 's/IPv6_address/IPV6_ADDRESS/g' ${ setupVars }
sed -i 's/piholeDNS1/PIHOLE_DNS_1/g' ${ setupVars }
sed -i 's/piholeDNS2/PIHOLE_DNS_2/g' ${ setupVars }
2016-11-01 10:36:59 +01:00
}
updatePihole( ) {
2016-11-02 10:33:17 +01:00
accountForRefactor
# Source ${setupVars} for use in the rest of the functions.
. ${ setupVars }
# Install base files and web interface
installScripts
installConfigs
CreateLogFile
configureSelinux
installPiholeWeb
installCron
configureFirewall
finalExports #re-export setupVars.conf to account for any new vars added in new versions
runGravity
2016-08-19 23:45:24 +02:00
}
2016-06-05 22:43:18 +02:00
configureSelinux( ) {
if [ -x " $( command -v getenforce) " ] ; then
printf "\n::: SELinux Detected\n"
printf ":::\tChecking for SELinux policy development packages..."
2016-10-10 11:24:03 +02:00
package_check_install "selinux-policy-devel" > /dev/null
echo " installed!"
2016-10-13 04:23:12 +02:00
printf ":::\tEnabling httpd server side includes (SSI).. "
2016-10-10 20:05:29 +02:00
setsebool -P httpd_ssi_exec on & > /dev/null && echo "Success" || echo "SELinux not enabled"
2016-09-08 04:06:36 +02:00
printf "\n:::\tCompiling Pi-Hole SELinux policy..\n"
2016-10-13 04:08:22 +02:00
if ! [ -x " $( command -v systemctl) " ] ; then
sed -i.bak '/systemd/d' /etc/.pihole/advanced/selinux/pihole.te
fi
2016-10-08 21:56:26 +02:00
checkmodule -M -m -o /etc/pihole/pihole.mod /etc/.pihole/advanced/selinux/pihole.te
semodule_package -o /etc/pihole/pihole.pp -m /etc/pihole/pihole.mod
semodule -i /etc/pihole/pihole.pp
rm -f /etc/pihole/pihole.mod
2016-10-10 20:05:29 +02:00
semodule -l | grep pihole & > /dev/null && echo "::: Installed Pi-Hole SELinux policy" || echo "::: Warning: Pi-Hole SELinux policy did not install."
2016-06-05 22:43:18 +02:00
fi
2015-11-07 19:07:50 +01:00
}
2016-01-27 07:11:38 +01:00
displayFinalMessage( ) {
2016-04-04 00:25:48 +02: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 03:26:05 +01:00
2016-11-01 10:45:22 +01:00
IPv4: ${ IPV4_ADDRESS %/* }
IPv6: ${ IPV6_ADDRESS }
2016-01-01 03:26:05 +01:00
2016-04-04 01:05:11 +02:00
If you set a new IP address, you should restart the Pi.
2016-01-01 03:26:05 +01:00
2016-05-26 00:55:36 +02:00
The install log is in /etc/pihole.
2016-11-01 10:45:22 +01:00
View the web interface at http://pi.hole/admin or http://${ IPV4_ADDRESS %/* } /admin" ${ r } ${ c }
2016-08-19 23:31:11 +02:00
}
2016-10-20 04:47:45 +02:00
update_dialogs( ) {
2016-10-22 08:57:47 +02:00
# reconfigure
if [ " ${ reconfigure } " = true ] ; then
opt1a = "Repair"
opt1b = "This will retain existing settings"
strAdd = "You will remain on the same version"
else
opt1a = "Update"
opt1b = "This will retain existing settings."
strAdd = "You will be updated to the latest version."
fi
opt2a = "Reconfigure"
opt2b = "This will allow you to enter new settings"
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 \
" ${ opt1a } " " ${ opt1b } " \
" ${ opt2a } " " ${ opt2b } " 3>& 2 2>& 1 1>& 3)
if [ [ $? = 0 ] ] ; then
case ${ UpdateCmd } in
${ opt1a } )
echo " ::: ${ opt1a } option selected. "
useUpdateVars = true
; ;
${ opt2a } )
echo " ::: ${ opt2a } option selected "
useUpdateVars = false
; ;
esac
else
echo "::: Cancel selected. Exiting..."
exit 1
fi
2016-08-19 23:31:11 +02:00
2016-01-01 03:26:05 +01:00
}
2016-10-08 21:17:04 +02:00
main( ) {
2016-10-15 21:52:20 +02:00
# Check arguments for the undocumented flags
2016-10-22 08:57:47 +02:00
for var in " $@ " ; do
case " $var " in
"--reconfigure" ) reconfigure = true; ;
"--i_do_not_follow_recommendations" ) skipSpaceCheck = false; ;
"--unattended" ) runUnattended = true; ;
esac
done
2016-05-01 08:27:46 +02:00
2016-10-22 08:57:47 +02:00
if [ [ -f ${ setupVars } ] ] ; then
if [ [ " ${ runUnattended } " = = true ] ] ; then
echo "::: --unattended passed to install script, no whiptail dialogs will be displayed"
useUpdateVars = true
else
update_dialogs
fi
fi
2016-10-02 12:09:14 +02:00
2016-10-22 08:57:47 +02:00
# Start the installer
# Verify there is enough disk space for the install
if [ [ " ${ skipSpaceCheck } " = = true ] ] ; then
echo "::: --i_do_not_follow_recommendations passed to script, skipping free disk space verification!"
else
verifyFreeDiskSpace
fi
2016-10-10 11:24:03 +02:00
2016-10-22 08:57:47 +02:00
# Update package cache
update_pacakge_cache
2016-10-10 11:24:03 +02:00
2016-10-22 08:57:47 +02:00
# Notify user of package availability
notify_package_updates_available
2016-05-01 08:27:46 +02:00
2016-10-22 08:57:47 +02:00
# Install packages used by this installation script
install_dependent_packages INSTALLER_DEPS[ @]
2016-10-10 19:36:19 +02:00
2016-10-22 08:57:47 +02:00
if [ [ " ${ reconfigure } " = = true ] ] ; then
echo "::: --reconfigure passed to install script. Not downloading/updating local repos"
else
# Get Git files for Core and Admin
2016-11-02 08:14:25 +01:00
getGitFiles ${ PI_HOLE_LOCAL_REPO } ${ piholeGitUrl }
2016-10-22 08:57:47 +02:00
getGitFiles ${ webInterfaceDir } ${ webInterfaceGitUrl }
fi
2016-02-10 16:34:06 +01:00
2016-10-22 08:57:47 +02:00
if [ [ ${ useUpdateVars } = = false ] ] ; then
# Display welcome dialogs
welcomeDialogs
# Create directory for Pi-hole storage
mkdir -p /etc/pihole/
# Remove legacy scripts from previous storage location
remove_legacy_scripts
# Stop resolver and webserver while installing proceses
stop_service dnsmasq
stop_service lighttpd
# Determine available interfaces
get_available_interfaces
# Find interfaces and let the user choose one
chooseInterface
# Let the user decide if they want to block ads over IPv4 and/or IPv6
use4andor6
# Decide what upstream DNS Servers to use
setDNS
2016-10-31 22:38:48 +01:00
# Let the user decide if they want query logging enabled...
setLogging
# Install packages used by the Pi-hole
2016-11-02 21:16:36 +01:00
install_dependent_packages PIHOLE_DEPS[ @]
2016-10-31 22:38:48 +01:00
2016-10-22 08:57:47 +02:00
# Install and log everything to a file
2016-11-02 13:17:28 +01:00
installPihole | tee ${ tmpLog }
2016-10-22 08:57:47 +02:00
else
2016-11-02 21:16:36 +01:00
# update packages used by the Pi-hole
install_dependent_packages PIHOLE_DEPS[ @]
2016-10-22 08:57:47 +02:00
updatePihole | tee ${ tmpLog }
fi
2015-11-07 19:35:08 +01:00
2016-10-22 08:57:47 +02:00
# Move the log file into /etc/pihole for storage
mv ${ tmpLog } ${ instalLogLoc }
2015-11-07 20:09:23 +01:00
2016-10-22 08:57:47 +02:00
if [ [ " ${ useUpdateVars } " = = false ] ] ; then
displayFinalMessage
fi
2016-02-06 14:02:21 +01:00
2016-10-22 08:57:47 +02:00
echo "::: Restarting services..."
# Start services
start_service dnsmasq
enable_service dnsmasq
start_service lighttpd
enable_service lighttpd
echo "::: done."
2016-08-21 19:00:41 +02:00
2016-10-22 08:57:47 +02:00
echo ":::"
if [ [ " ${ useUpdateVars } " = = false ] ] ; then
echo "::: Installation Complete! Configure your devices to use the Pi-hole as their DNS server using:"
2016-11-01 10:45:22 +01:00
echo " ::: ${ IPV4_ADDRESS %/* } "
echo " ::: ${ IPV6_ADDRESS } "
2016-10-22 08:57:47 +02:00
echo ":::"
echo "::: If you set a new IP address, you should restart the Pi."
2016-11-02 21:16:36 +01:00
echo " ::: View the web interface at http://pi.hole/admin or http:// ${ IPV4_ADDRESS %/* } /admin "
2016-10-22 08:57:47 +02:00
else
echo "::: Update complete!"
fi
echo ":::"
echo "::: The install log is located at: /etc/pihole/install.log"
2016-10-08 21:17:04 +02:00
}
2016-11-03 04:13:05 +01:00
if [ [ " ${ PHTEST } " != "TRUE" ] ] ; then
2016-10-11 06:14:39 +02:00
main " $@ "
fi