diff --git a/README.md b/README.md index fd26050..1e90041 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # synchole -Shell script to syncronize two or more [pi-hole](https://pi-hole.net) servers. It replicates all changes to _blacklist.txt_, _whitelist.txt_, _regex.list_, _/etc/hosts_ and runs `updateGravity`/`restartdns` on all members. +Shell script to syncronize a SLAVE [pi-hole](https://pi-hole.net) server with a MASTER pi-hole server. It downloads _blacklist.txt_, _whitelist.txt_ and _regex.list_ from the MASTER, updates local files and runs `updateGravity` on the SLAVE. ## Setup 1. Login via SSH to the `MASTER` server. -2. Create symlinks for all files you want to sync within the webroot of the `MASTER` pihole. +2. Create symlinks for all files you want to be able to sync within the webroot of the `MASTER` pihole. ``` cd /var/www/html sudo mkdir synchole @@ -19,13 +19,15 @@ sudo ln -s /etc/pihole/regex.list . 3. Login via SSH to the `SLAVE` server. -4. Install synchole on the `SLAVE` server. +4. Install _wget_ and _[synchole](https://socialg.it/david/synchole)_ on the `SLAVE` server. ``` -cd /opt -sudo git clone https://socialg.it/david/synchole.git +sudo apt-get update +sudo apt-get install wget +sudo wget https://socialg.it/david/synchole/raw/master/synchole.sh -O /usr/bin/synchole.sh +sudo chmod +x /usr/bin/synchole.sh ``` -5. Configure the synchole script. +5. Configure the synchole script to your liking. ``` sudo vim /opt/synchole.sh ``` @@ -35,14 +37,9 @@ The config section is at the top of the script. ``` sudo crontab -e ``` -Example cronjob: `*/5 * * * * /opt/synchole/synchole.sh -q` (this runs the synchole every 5 minutes) +Example cronjob: `*/5 * * * * /opt/synchole/synchole.sh -q` (this runs synchole every 5 minutes) -7. Setup postfix to send notifications (from cron) on the `SLAVE` server. -``` - -``` - -8. Repeat steps 3 through 7 for additional `SLAVE` servers. +8. Repeat steps 3 through 6 for additional `SLAVE` servers. 9. Happy syncholeing! diff --git a/synchole.sh b/synchole.sh index 5f3c94c..46fec0d 100755 --- a/synchole.sh +++ b/synchole.sh @@ -2,23 +2,25 @@ # # synchole.sh +# Pi-Hole syncronizer # # **** configuration **** -LISTS="whitelist.txt blacklist.txt regex.list" #pihole files to sync -LISTS_PATH="/etc/pihole" #pihole files path MASTER="10.1.3.2" #IP or hostname of the MASTER server DEBUG=1 #enable verbose output (1=on, 0=off) -BACKUP_PATH="/etc/pihole/synchole-backups" #path to backups BACKUP_VERSIONS=10 #how many backups should be kept -TEMP_PATH="/tmp/synchole-downloads" #path to list downloads -DEPENDENCIES="wget" +BACKUP_PATH="/etc/pihole/synchole-backups" #path to backups +DOWNLOAD_PATH="/tmp/synchole-downloads" #path to list downloads + +LISTS="whitelist.txt blacklist.txt regex.list" #pihole files to sync +LISTS_PATH="/etc/pihole" #pihole files path NAME="synchole" VERSION="0.1" AUTHOR="david@socialnerds.org" LICENSE="GPLv3" +DEPENDENCIES="wget" # **** functions **** @@ -30,20 +32,13 @@ amiroot() { fi } -## check for local environment +## check if pi-hole is installed amipihole() { if [ ! $(which pihole) ]; then return 1 fi } -## check if system is debian based -amidebian() { - if [ ! $(which apt-get) ]; then - return 1 - fi -} - ## output handling log() { case $1 in @@ -55,43 +50,23 @@ log() { ;; "debug") if [ $DEBUG -eq 1 ]; then - level="\033[2md\033[0m" + level="\033[2md\033[0m" else - return 0 + return 0 fi ;; "success") level="\033[32m✓\033[0m" ;; "info") - level=">" + level="i" ;; *) level="\033[31mLoglevel unknown. Programming error? ($*)\033[0m" ;; esac - sleep 0.4; echo -e "[$NAME][$level] $2" -} - -## update package sources -update_repos() { - apt-get update > /dev/null - if [ $? -ne 0 ]; then - return 1 - fi -} - -## install debian package -install_package() { - if [ -n $1 ]; then - apt-get install -y $1 &> /dev/null - if [ $? -ne 0 ]; then - return 1 - fi - else - return 1 - fi + sleep 0.5; echo -e "[$level] $2" } ## backup single list file to $BACKUP_PATH @@ -101,11 +76,11 @@ backup_list() { else for VERSION in $(eval echo {$BACKUP_VERSIONS..1}); do if [ -w $BACKUP_PATH/$1.$VERSION ]; then - if [ $VERSION -eq $BACKUP_VERSIONS ]; then - rm $BACKUP_PATH/$1.$VERSION - else - mv $BACKUP_PATH/$1.$VERSION $BACKUP_PATH/$1.$(($VERSION+1)) - fi + if [ $VERSION -eq $BACKUP_VERSIONS ]; then + rm $BACKUP_PATH/$1.$VERSION + else + mv $BACKUP_PATH/$1.$VERSION $BACKUP_PATH/$1.$(($VERSION+1)) + fi fi done if [ -w $BACKUP_PATH/$1 ]; then @@ -120,79 +95,100 @@ backup_list() { fi } -# **** start of script **** +## create path/to/folder if it does not exist +create_path() { + if [ -z $1 ]; then + return 1 + else + if [ ! -d $1 ]; then + mkdir -p $1 + if [ $? -ne 0 ]; then + return 1 + fi + fi + fi +} -log info "Commencing preflight checks." +## update pi-hole lists (run updateGravity) +update_gravity() { + pihole -g > /dev/null + if [ $? -ne 0 ]; then + return 1 + fi +} + +## install new list +install_list() { + if [ -z $1 ]; then + return 1 + else + cp $DOWNLOAD_PATH/$1 $LISTS_PATH/$1 + if [ $? -ne 0 ]; then + return 1 + fi + fi +} + +## download remote file +download_list() { + if [ -z $1 ]; then + return 1 + else + wget http://$MASTER/synchole/$1 -q -O $DOWNLOAD_PATH/$1 + if [ $? -ne 0 ]; then + return 1 + fi + fi +} + +# **** start of script **** ## preflight checks if ! amiroot; then - log error "You must be root. Exiting." + log error "You must be root" exit 1 -else - log debug "I am root. Continuing." -fi - -if ! amidebian; then - log error "I am no debian based system. Exiting." - exit 1 -else - log debug "I am debian based. Continuing." fi if ! amipihole; then - log error "I am no pihole. Exiting." - exit 1 -else - log debug "I am a pihole system. Continuing." + log error "I am no pihole" + exit 1 fi for DEPENDENCY in $DEPENDENCIES; do - if install_package $DEPENDENCY; then - log debug "$DEPENDENCY successfully installed. Continuing." - else - log error "$DEPENDENCY could not be installed. Exiting." + if ! $(which $DEPENDENCY); then + log error "$DEPENDENCY is not installed" exit 1 fi done -log success "Preflight checks passed." +log success "Preflight checks passed" -## generate $BACKUP_PATH and $TEMP_PATH if not available -if [ ! -d $BACKUP_PATH ]; then - log info "$BACKUP_PATH does not exist. Creating." - mkdir -p $BACKUP_PATH - if [ $? -ne 0 ]; then - log error "Something went wrong while creating $BACKUP_PATH. Exiting." - exit 1 - fi -else - log debug "$BACKUP_PATH exists. Continuing" +## generate $BACKUP_PATH and $DOWNLOAD_PATH if not available +if ! create_path $DOWNLOAD_PATH; then + log error "Something went wrong while creating $DOWNLOAD_PATH" + exit 1 fi -if [ ! -d $TEMP_PATH ]; then - log info "$BACKUP_PATH does not exist. Creating." - mkdir -p $TEMP_PATH - if [ $? -ne 0 ]; then - log error "Something went wrong while creating $TEMP_PATH. Exiting." - exit 1 - fi -else - log debug "$TEMP_PATH exists. Continuing." +if ! create_path $BACKUP_PATH; then + log error "Something went wrong while creating $BACKUP_PATH" + exit 1 fi ## download remote files from MASTER and backup local lists CHANGES=0 for LIST in $LISTS; do log info "Downloading $LIST." - wget http://$MASTER/synchole/$LIST -q -O $TEMP_PATH/$LIST - if [ $? -ne 0 ]; then - log error "Something went wrong while downloading http://$MASTER/synchole/$LIST. Exiting." + if ! download_list $LIST; then + log error "Something went wrong while downloading $LIST" exit 1 else log success "Successfully downloaded $LIST." fi - diff $TEMP_PATH/$LIST $LISTS_PATH/$LIST + #TODO: don't install new list if to many changes or + # somehow verify if new file is an actual list + # maybe check if wget actually downloaded a file or were we redirected + diff $DOWNLOAD_PATH/$LIST $LISTS_PATH/$LIST if [ $? -ne 0 ]; then log info "Backing up $LIST." if [ -r $LISTS_PATH/$LIST ]; then @@ -207,33 +203,28 @@ for LIST in $LISTS; do fi log info "Installing $LIST." - cp $TEMP_PATH/$LIST $LISTS_PATH/$LIST - if [ $? -ne 0 ]; then - log error "Something went wrong installing updated file to $LIST_PATH/$LIST" + if ! install_list $LIST; then + log error "Something went wrong while installing $LIST" else - log success "Successfully installed updated $LIST." + log success "Successfully installed $LIST" CHANGES=1 fi else - log warn "No changes in $LIST. Skipping." + log debug "No changes in $LIST" fi done -#run updateGravity +## run updateGravity if [ $CHANGES -eq 1 ]; then - pihole -g > /dev/null - if [ $? -ne 0 ]; then - log error "Something went wrong while updating Gravity. Exiting." + if update_gravity; then + log error "Something went wrong while updating gravity" else - log success "Successfully updated Gravity." + log success "Gravity has been successfully updated" fi else - log warn "No files have been changed. Skipping Gravity update." + log debug "No files have been changed, skipping gravity update" fi -#run restartdns (if hosts.list has been updated) - -log success "Touchdown." exit 0 # **** end of script ****