diff --git a/CHANGELOG.md b/CHANGELOG.md index 7020a99..6d757b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # The Changelog +## 3.2 + +### The Alias Release + +This release now fully supports Pi-hole 5.2, specifically the CNAME replication features that were added. Because the location of these settings is in a new directory that was not previously monitored by Gravity Sync, you will need to opt-in to replication by updating your configuration file to enable support for replicating this. + +- New setups can be prompted to enable this during configuration using the Advanced Configuration options. +- Existing installs wishing to make sure of this feature, should either re-run the `./gravity-sync config` command, or manually edit the `gravity-sync.conf` to set `INCLUDE_CNAME='1'`. +- Before you enable `INCLUDE_CNAME` make sure you've created at least one entry from within the primary Pi-hole interface, otherwise Gravity Sync will have nothing to replicate as the files will not yet exist. +- You cannot enable `INCLUDE_CNAME` if you've also enabled `SKIP_CUSTOM` as the CNAME function is dependent on Local DNS records. You can, however, only replicate the Local DNS Records if you do not intend to leverage CNAME records. +- Existing installs using Docker, or otherwise using a non-standard location for dnsmasq configuration files (default is `/etc/dnsmasq.d`) will also need to manually specify the location of these files. +- See the [Hidden Figures](https://github.com/vmstan/gravity-sync/wiki/Hidden-Figures) document for more details. + +#### More Syncing Coming + +Even before the Pi-hole team added the CNAME feature and implemented in such a way that the `/etc/dnsmasq.d` would need to be seen by Gravity Sync, I have had a desire to replicate additional custom files here for my own selfish needs. More people asked for a similar function, and now that it's required to be built into the core script, it's easier to include these additional files. + +Not implemented in 3.2.0, but coming within this release, Gravity Sync will be configured to monitor a custom file of your creation in this folder (default is `08-gs-lan.conf`) which can contain additional configuration options for DNSMASQ. + +An example would be setting different caching options for Pi-hole, or specifying the lookup targets for additional networks. Similar requirements as above for the CNAME syncing must be met for existing installs to leverage this functionality. + ## 3.1 ### The Container Release diff --git a/README.md b/README.md index 8712d24..9720b0e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Gravity Sync

-What is better than a [Pi-hole](https://github.com/pi-hole/pi-hole) blocking ads via DNS on your network? That's right, **two** Pi-hole blocking ads on your network! +What is better than a [Pi-hole](https://github.com/pi-hole/pi-hole) blocking ads via DNS on your network? That's right, **two** Pi-hole blocking ads on your network! - [Seriously. Why two Pi-hole?](https://github.com/vmstan/gravity-sync/wiki/Frequent-Questions#why-do-i-need-more-than-one-pi-hole) @@ -11,11 +11,16 @@ But if you have more than one Pi-hole in your network you'll want a simple way t # Features Gravity Sync replicates the `gravity.db` database, which includes: + - Blocklist settings with status and comments. - Domain whitelist and blacklist along with status with comments. - Custom RegEx whitelist and blacklists. - Clients and groups along with any list assignments. -- Local DNS Settings (These are stored in a separate `custom.list` file and can optionally be disabled.) + +Gravity Sync can also (optionally) replicate FTLDNS/DNSMASQ configuration files, including: + +- Local DNS (A Records) which are stored in a separate `custom.list` file within the `/etc/pihole` directory. +- CNAME Records which are stored in a separate `05-pihole-custom-cname.conf` file in the `/etc/dnsmasq.d` directory. ### Limitations diff --git a/VERSION b/VERSION index 6ebad14..a4f52a5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.1.2 \ No newline at end of file +3.2.0 \ No newline at end of file diff --git a/gravity-sync.conf.example b/gravity-sync.conf.example index ad33cb1..2b7547b 100644 --- a/gravity-sync.conf.example +++ b/gravity-sync.conf.example @@ -15,6 +15,8 @@ REMOTE_USER='pi' ### Pi-hole Folder/File Customization # PIHOLE_DIR='' # default Pi-hole data directory (local) # RIHOLE_DIR='' # default Pi-hole data directory (remote) +# DNSMAQ_DIR='' # default DNSMASQ data directory (local) +# RNSMAQ_DIR='' # default DNSMASQ data directory (remote) # PIHOLE_BIN='' # default Pi-hole binary directory (local) # RIHOLE_BIN='' # default Pi-hole binary directory (remote) # DOCKER_BIN='' # default Docker binary directory (local) @@ -26,10 +28,13 @@ REMOTE_USER='pi' # GRAVITY_FI='' # default Pi-hole database file # CUSTOM_DNS='' # default Pi-hole local DNS lookups +# CNAME_CONF='' # default DNSMASQ CNAME alias file +# GSLAN_CONF='' # default DNSMASQ GS managed file ### Interaction Customization # VERIFY_PASS='' # replace in gravity-sync.conf to overwrite # SKIP_CUSTOM='' # replace in gravity-sync.conf to overwrite +# INCLUDE_CNAME='' # replace in gravity-sync.conf to overwrite # DATE_OUTPUT='' # replace in gravity-sync.conf to overwrite # PING_AVOID='' # replace in gravity-sync.conf to overwrite # ROOT_CHECK_AVOID='' # replace in gravity-sync.conf to overwrite diff --git a/gravity-sync.sh b/gravity-sync.sh index 5592c7f..e7a0edd 100755 --- a/gravity-sync.sh +++ b/gravity-sync.sh @@ -3,7 +3,7 @@ SCRIPT_START=$SECONDS # GRAVITY SYNC BY VMSTAN ##################### PROGRAM='Gravity Sync' -VERSION='3.1.2' +VERSION='3.2.0' # For documentation or downloading updates visit https://github.com/vmstan/gravity-sync # Requires Pi-Hole 5.x or higher already be installed, for help visit https://pi-hole.net @@ -23,6 +23,8 @@ RH_IN_TYPE='default' # Pi-hole install type, `default` or `docker` (remote) # Pi-hole Folder/File Customization PIHOLE_DIR='/etc/pihole' # default Pi-hole data directory (local) RIHOLE_DIR='/etc/pihole' # default Pi-hole data directory (remote) +DNSMAQ_DIR='/etc/dnsmasq.d' # default DNSMASQ data directory (local) +RNSMAQ_DIR='/etc/dnsmasq.d' # default DNSMASQ data directory (remote) PIHOLE_BIN='/usr/local/bin/pihole' # default Pi-hole binary directory (local) RIHOLE_BIN='/usr/local/bin/pihole' # default Pi-hole binary directory (remote) DOCKER_BIN='/usr/bin/docker' # default Docker binary directory (local) @@ -32,12 +34,15 @@ RILE_OWNER='pihole:pihole' # default Pi-hole file owner and group (remote) DOCKER_CON='pihole' # default Pi-hole Docker container name (local) ROCKER_CON='pihole' # default Pi-hole Docker container name (remote) -GRAVITY_FI='gravity.db' # default Pi-hole database file -CUSTOM_DNS='custom.list' # default Pi-hole local DNS lookups +GRAVITY_FI='gravity.db' # default Pi-hole database file +CUSTOM_DNS='custom.list' # default Pi-hole local DNS lookups +CNAME_CONF='05-pihole-custom-cname.conf' # default DNSMASQ CNAME alias file +GSLAN_CONF='08-gs-lan.conf' # default DNSMASQ GS managed file # Interaction Customization VERIFY_PASS='0' # replace in gravity-sync.conf to overwrite SKIP_CUSTOM='0' # replace in gravity-sync.conf to overwrite +INCLUDE_CNAME='0' # replace in gravity-sync.conf to overwrite DATE_OUTPUT='0' # replace in gravity-sync.conf to overwrite PING_AVOID='0' # replace in gravity-sync.conf to overwrite ROOT_CHECK_AVOID='0' # replace in gravity-sync.conf to overwrite diff --git a/includes/gs-backup.sh b/includes/gs-backup.sh index e72a24a..ffc75bf 100644 --- a/includes/gs-backup.sh +++ b/includes/gs-backup.sh @@ -13,6 +13,7 @@ function task_backup { backup_settime backup_local_gravity backup_local_custom + backup_local_cname backup_cleanup logs_export @@ -41,6 +42,26 @@ function backup_local_custom { cp ${PIHOLE_DIR}/${CUSTOM_DNS} ${LOCAL_FOLDR}/${BACKUP_FOLD}/${BACKUPTIMESTAMP}-${CUSTOM_DNS}.backup error_validate + else + MESSAGE="No Local ${CUSTOM_DNS} Detected" + echo_info + fi + fi +} + +function backup_local_cname { + if [ "${INCLUDE_CNAME}" == '1' ] + then + if [ -f ${DNSMAQ_DIR}/${CNAME_CONF} ] + then + MESSAGE="Performing Backup Up Local ${CNAME_CONF}" + echo_stat + + cp ${DNSMAQ_DIR}/${CNAME_CONF} ${LOCAL_FOLDR}/${BACKUP_FOLD}/${BACKUPTIMESTAMP}-${CNAME_CONF}.backup + error_validate + else + MESSAGE="No Local ${CNAME_CONF} Detected" + echo_info fi fi } @@ -66,6 +87,18 @@ function backup_remote_custom { fi } +function backup_remote_cname { + if [ "$INCLUDE_CNAME" == '1' ] + then + MESSAGE="Performing Backup of Remote ${CNAME_CONF}" + echo_stat + + CMD_TIMEOUT='15' + CMD_REQUESTED="sudo cp ${RNSMAQ_DIR}/${CNAME_CONF} ${RIHOLE_DIR}/dnsmasq.d-${CNAME_CONF}.backup" + create_sshcmd + fi +} + function backup_cleanup { MESSAGE="Cleaning Up Old Backups" echo_stat diff --git a/includes/gs-compare.sh b/includes/gs-compare.sh index 7fb4017..2635534 100644 --- a/includes/gs-compare.sh +++ b/includes/gs-compare.sh @@ -1,3 +1,9 @@ +# GRAVITY SYNC BY VMSTAN ##################### +# gs-compare.sh ############################## + +# For documentation or downloading updates visit https://github.com/vmstan/gravity-sync +# This code is called from the main gravity-sync.sh file and should not execute directly! + ## Compare Task function task_compare { TASKTYPE='COMPARE' @@ -7,6 +13,12 @@ function task_compare { show_target validate_gs_folders validate_ph_folders + + if [ "${INCLUDE_CNAME}" == "1" ] + then + validate_dns_folders + fi + validate_os_sshpass previous_md5 diff --git a/includes/gs-config.sh b/includes/gs-config.sh index 550105d..7b006e1 100644 --- a/includes/gs-config.sh +++ b/includes/gs-config.sh @@ -151,6 +151,23 @@ function advanced_config_generate { exit_withchanges fi + MESSAGE="Local DNSMASQ 'etc' Volume Path? (Required, no trailing slash)" + echo_need + read INPUT_DNSMAQ_DIR + + if [ "${INPUT_DNSMAQ_DIR}" != "" ] + then + MESSAGE="Saving Local DNSMASQ Volume to ${CONFIG_FILE}" + echo_stat + sed -i "/# DNSMAQ_DIR=''/c\DNSMAQ_DIR='${INPUT_DNSMAQ_DIR}'" ${LOCAL_FOLDR}/${CONFIG_FILE} + error_validate + SKIP_DNSMAQ_DIR="1" + else + MESSAGE="This setting is required!" + echo_warn + exit_withchanges + fi + MESSAGE="Saving Local Volume Ownership to ${CONFIG_FILE}" echo_stat sed -i "/# FILE_OWNER=''/c\FILE_OWNER='named:docker'" ${LOCAL_FOLDR}/${CONFIG_FILE} @@ -199,6 +216,23 @@ function advanced_config_generate { exit_withchanges fi + MESSAGE="Remote DNSMASQ 'etc' Volume Path? (Required, no trailing slash)" + echo_need + read INPUT_RNSMAQ_DIR + + if [ "${INPUT_RNSMAQ_DIR}" != "" ] + then + MESSAGE="Saving Remote DNSMASQ Volume to ${CONFIG_FILE}" + echo_stat + sed -i "/# RNSMAQ_DIR=''/c\RNSMAQ_DIR='${INPUT_RNSMAQ_DIR}'" ${LOCAL_FOLDR}/${CONFIG_FILE} + error_validate + SKIP_RNSMAQ_DIR="1" + else + MESSAGE="This setting is required!" + echo_warn + exit_withchanges + fi + MESSAGE="Saving Remote Volume Ownership to ${CONFIG_FILE}" echo_stat sed -i "/# RILE_OWNER=''/c\RILE_OWNER='named:docker'" ${LOCAL_FOLDR}/${CONFIG_FILE} @@ -238,6 +272,38 @@ function advanced_config_generate { fi fi + if [ "$SKIP_DNSMASQ_DIR" != "1" ] + then + MESSAGE="Local DNSMASQ Settings Directory Path? (Leave blank for default '/etc/dnsmasq.d')" + echo_need + read INPUT_DNSMASQ_DIR + INPUT_DNSMASQ_DIR="${INPUT_DNSMASQ_DIR:-/etc/dnsmasq.d}" + + if [ "${INPUT_DNSMASQ_DIR}" != "/etc/dnsmasq.d" ] + then + MESSAGE="Saving Local DNSMASQ Settings Directory Path to ${CONFIG_FILE}" + echo_stat + sed -i "/# DNSMASQ_DIR=''/c\DNSMASQ_DIR='${INPUT_DNSMASQ_DIR}'" ${LOCAL_FOLDR}/${CONFIG_FILE} + error_validate + fi + fi + + if [ "$SKIP_RNSMASQ_DIR" != "1" ] + then + MESSAGE="Remote DNSMASQ Settings Directory Path? (Leave blank for default '/etc/dnsmasq.d')" + echo_need + read INPUT_RNSMASQ_DIR + INPUT_RNSMASQ_DIR="${INPUT_RNSMASQ_DIR:-/etc/dnsmasq.d}" + + if [ "${INPUT_RNSMASQ_DIR}" != "/etc/dnsmasq.d" ] + then + MESSAGE="Saving Remote DNSMASQ Settings Directory Path to ${CONFIG_FILE}" + echo_stat + sed -i "/# RNSMASQ_DIR=''/c\RNSMASQ_DIR='${INPUT_RNSMASQ_DIR}'" ${LOCAL_FOLDR}/${CONFIG_FILE} + error_validate + fi + fi + MESSAGE="Use Custom SSH Port? (Leave blank for default '22')" echo_need read INPUT_SSH_PORT @@ -292,6 +358,22 @@ function advanced_config_generate { error_validate fi + if [ "${INPUT_SKIP_CUSTOM}" == "Y" ] + then + MESSAGE="Enable Replicate 'Local CNAME Records' Feature? (Leave blank for default 'Yes')" + echo_need + read INPUT_INCLUDE_CNAME + INPUT_INCLUDE_CNAME="${INPUT_INCLUDE_CNAME:-Y}" + + if [ "${INPUT_INCLUDE_CNAME}" == "Y" ] + then + MESSAGE="Saving Local CNAME Preference to ${CONFIG_FILE}" + echo_stat + sed -i "/# INCLUDE_CNAME=''/c\INCLUDE_CNAME='1'" ${LOCAL_FOLDR}/${CONFIG_FILE} + error_validate + fi + fi + MESSAGE="Change Backup Retention in Days? (Leave blank for default '7')" echo_need read INPUT_BACKUP_RETAIN diff --git a/includes/gs-core.sh b/includes/gs-core.sh index b98ed33..599f884 100644 --- a/includes/gs-core.sh +++ b/includes/gs-core.sh @@ -59,7 +59,7 @@ function ph_type { RH_EXEC="${RIHOLE_BIN}" elif [ "$RH_IN_TYPE" == "docker" ] then - RH_EXEC="${ROCKER_BIN} exec ${DOCKER_CON} pihole" + RH_EXEC="${ROCKER_BIN} exec ${ROCKER_CON} pihole" fi } @@ -79,6 +79,14 @@ function start_gs { then new_root_check fi + + if [ "${INCLUDE_CNAME}" == "1" ] && [ "${SKIP_CUSTOM}" == "1" ] + then + MESSAGE="Invalid Local DNS Settings in ${CONFIG_FILE}" + echo_fail + + exit_nochange + fi } # Standard Output No Config diff --git a/includes/gs-hashing.sh b/includes/gs-hashing.sh index c3ff50d..6d21d9e 100644 --- a/includes/gs-hashing.sh +++ b/includes/gs-hashing.sh @@ -70,6 +70,53 @@ function md5_compare { fi fi + if [ "${SKIP_CUSTOM}" != '1' ] + then + if [ "${INCLUDE_CNAME}" == "1" ] + then + if [ -f ${DNSMAQ_DIR}/${CNAME_CONF} ] + then + if ${SSHPASSWORD} ${SSH_CMD} -p ${SSH_PORT} -i "$HOME/${SSH_PKIF}" ${REMOTE_USER}@${REMOTE_HOST} test -e ${RNSMAQ_DIR}/${CNAME_CONF} + then + REMOTE_CNAME_DNS="1" + MESSAGE="Analyzing ${CNAME_CONF} on ${REMOTE_HOST}" + echo_stat + + primaryCNMD5=$(${SSHPASSWORD} ${SSH_CMD} -p ${SSH_PORT} -i "$HOME/${SSH_PKIF}" ${REMOTE_USER}@${REMOTE_HOST} "md5sum ${RNSMAQ_DIR}/${CNAME_CONF} | sed 's/\s.*$//'") + error_validate + + MESSAGE="Analyzing ${CNAME_CONF} on $HOSTNAME" + echo_stat + secondCNMD5=$(md5sum ${DNSMAQ_DIR}/${CNAME_CONF} | sed 's/\s.*$//') + error_validate + + if [ "$primaryCNMD5" == "$last_primaryCNMD5" ] && [ "$secondCNMD5" == "$last_secondCNMD5" ] + then + HASHMARK=$((HASHMARK+0)) + else + MESSAGE="Differenced ${CNAME_CONF} Detected" + echo_warn + HASHMARK=$((HASHMARK+1)) + fi + else + MESSAGE="No ${CNAME_CONF} Detected on ${REMOTE_HOST}" + echo_info + fi + else + if ${SSHPASSWORD} ${SSH_CMD} -p ${SSH_PORT} -i "$HOME/${SSH_PKIF}" ${REMOTE_USER}@${REMOTE_HOST} test -e ${RNSMAQ_DIR}/${CNAME_CONF} + then + REMOTE_CNAME_DNS="1" + MESSAGE="${REMOTE_HOST} has ${CNAME_CONF}" + HASHMARK=$((HASHMARK+1)) + echo_info + fi + + MESSAGE="No ${CNAME_CONF} Detected on $HOSTNAME" + echo_info + fi + fi + fi + if [ "$HASHMARK" != "0" ] then MESSAGE="Replication Required" @@ -89,11 +136,15 @@ function previous_md5 { last_secondDBMD5=$(sed "2q;d" ${LOG_PATH}/${HISTORY_MD5}) last_primaryCLMD5=$(sed "3q;d" ${LOG_PATH}/${HISTORY_MD5}) last_secondCLMD5=$(sed "4q;d" ${LOG_PATH}/${HISTORY_MD5}) + last_primaryCNMD5=$(sed "5q;d" ${LOG_PATH}/${HISTORY_MD5}) + last_secondCNMD5=$(sed "6q;d" ${LOG_PATH}/${HISTORY_MD5}) else last_primaryDBMD5="0" last_secondDBMD5="0" last_primaryCLMD5="0" last_secondCLMD5="0" + last_primaryCNMD5="0" + last_secondCNMD5="0" fi } @@ -145,4 +196,41 @@ function md5_recheck { echo_info fi fi + + if [ "${SKIP_CUSTOM}" != '1' ] + then + if [ "${INCLUDE_CNAME}" == "1" ] + then + if [ -f ${DNSMAQ_DIR}/${CNAME_CONF} ] + then + if ${SSHPASSWORD} ${SSH_CMD} -p ${SSH_PORT} -i "$HOME/${SSH_PKIF}" ${REMOTE_USER}@${REMOTE_HOST} test -e ${RNSMAQ_DIR}/${CNAME_CONF} + then + REMOTE_CNAME_DNS="1" + MESSAGE="Reanalyzing ${CNAME_CONF} on ${REMOTE_HOST}" + echo_stat + + primaryCNMD5=$(${SSHPASSWORD} ${SSH_CMD} -p ${SSH_PORT} -i "$HOME/${SSH_PKIF}" ${REMOTE_USER}@${REMOTE_HOST} "md5sum ${RNSMAQ_DIR}/${CNAME_CONF} | sed 's/\s.*$//'") + error_validate + + MESSAGE="Reanalyzing ${CNAME_CONF} on $HOSTNAME" + echo_stat + secondCNMD5=$(md5sum ${DNSMAQ_DIR}/${CNAME_CONF} | sed 's/\s.*$//') + error_validate + else + MESSAGE="No ${CNAME_CONF} Detected on ${REMOTE_HOST}" + echo_info + fi + else + if ${SSHPASSWORD} ${SSH_CMD} -p ${SSH_PORT} -i "$HOME/${SSH_PKIF}" ${REMOTE_USER}@${REMOTE_HOST} test -e ${RNSMAQ_DIR}/${CNAME_CONF} + then + REMOTE_CNAME_DNS="1" + MESSAGE="${REMOTE_HOST} has ${CNAME_CONF}" + echo_info + fi + + MESSAGE="No ${CNAME_CONF} Detected on $HOSTNAME" + echo_info + fi + fi + fi } \ No newline at end of file diff --git a/includes/gs-logging.sh b/includes/gs-logging.sh index e598921..e8de821 100644 --- a/includes/gs-logging.sh +++ b/includes/gs-logging.sh @@ -25,6 +25,8 @@ function logs_export { echo -e ${secondDBMD5} >> ${LOG_PATH}/${HISTORY_MD5} echo -e ${primaryCLMD5} >> ${LOG_PATH}/${HISTORY_MD5} echo -e ${secondCLMD5} >> ${LOG_PATH}/${HISTORY_MD5} + echo -e ${primaryCNMD5} >> ${LOG_PATH}/${HISTORY_MD5} + echo -e ${secondCNMD5} >> ${LOG_PATH}/${HISTORY_MD5} error_validate fi diff --git a/includes/gs-pull.sh b/includes/gs-pull.sh index 856690f..642b49d 100644 --- a/includes/gs-pull.sh +++ b/includes/gs-pull.sh @@ -13,6 +13,12 @@ function task_pull { show_target validate_gs_folders validate_ph_folders + + if [ "${INCLUDE_CNAME}" == "1" ] + then + validate_dns_folders + fi + validate_sqlite3 validate_os_sshpass @@ -154,6 +160,37 @@ function pull_gs_cust { fi } +## Pull CNAME +function pull_gs_cname { + if [ "${INCLUDE_CNAME}" == '1' ] + then + if [ "$REMOTE_CNAME_DNS" == "1" ] + then + backup_local_cname + backup_remote_cname + + MESSAGE="Pulling ${CNAME_CONF} from ${REMOTE_HOST}" + echo_stat + RSYNC_REPATH="rsync" + RSYNC_SOURCE="${REMOTE_USER}@${REMOTE_HOST}:${RIHOLE_DIR}/dnsmasq.d-${CNAME_CONF}.backup" + RSYNC_TARGET="${LOCAL_FOLDR}/${BACKUP_FOLD}/${CNAME_CONF}.pull" + create_rsynccmd + + MESSAGE="Replacing ${CNAME_CONF} on $HOSTNAME" + echo_stat + sudo cp ${LOCAL_FOLDR}/${BACKUP_FOLD}/${CNAME_CONF}.pull ${DNSMAQ_DIR}/${CNAME_CONF} >/dev/null 2>&1 + error_validate + + MESSAGE="Validating Settings on ${CNAME_CONF}" + echo_stat + + validate_cname_permissions + + echo_good + fi + fi +} + ## Pull Reload function pull_gs_reload { MESSAGE="Isolating Regeneration Pathways" @@ -179,6 +216,7 @@ function pull_gs { backup_settime pull_gs_grav pull_gs_cust + pull_gs_cname pull_gs_reload md5_recheck diff --git a/includes/gs-push.sh b/includes/gs-push.sh index 5d8b373..18d5e01 100644 --- a/includes/gs-push.sh +++ b/includes/gs-push.sh @@ -13,6 +13,12 @@ function task_push { show_target validate_gs_folders validate_ph_folders + + if [ "${INCLUDE_CNAME}" == "1" ] + then + validate_dns_folders + fi + validate_sqlite3 validate_os_sshpass @@ -90,6 +96,44 @@ function push_gs_cust { fi } +## Push Custom +function push_gs_cname { + if [ "${INCLUDE_CNAME}" == '1' ] + then + if [ "$REMOTE_CNAME_DNS" == "1" ] + then + backup_remote_cname + backup_local_cname + + MESSAGE="Copying ${CNAME_CONF} from ${REMOTE_HOST}" + echo_stat + RSYNC_REPATH="rsync" + RSYNC_SOURCE="${REMOTE_USER}@${REMOTE_HOST}:${RIHOLE_DIR}/dnsmasq.d-${CNAME_CONF}.backup" + RSYNC_TARGET="${LOCAL_FOLDR}/${BACKUP_FOLD}/${CNAME_CONF}.push" + create_rsynccmd + + MESSAGE="Pushing ${CNAME_CONF} to ${REMOTE_HOST}" + echo_stat + RSYNC_REPATH="sudo rsync" + RSYNC_SOURCE="${LOCAL_FOLDR}/${BACKUP_FOLD}/${BACKUPTIMESTAMP}-${CNAME_CONF}.backup" + RSYNC_TARGET="${REMOTE_USER}@${REMOTE_HOST}:${RNSMAQ_DIR}/${CNAME_CONF}" + create_rsynccmd + + MESSAGE="Setting Permissions on ${CNAME_CONF}" + echo_stat + CMD_TIMEOUT='15' + CMD_REQUESTED="sudo chmod 644 ${RNSMAQ_DIR}/${CNAME_CONF}" + create_sshcmd + + MESSAGE="Setting Ownership on ${CNAME_CONF}" + echo_stat + CMD_TIMEOUT='15' + CMD_REQUESTED="sudo chown root:root ${RNSMAQ_DIR}/${CNAME_CONF}" + create_sshcmd + fi + fi +} + ## Push Reload function push_gs_reload { MESSAGE="Inverting Tachyon Pulses" @@ -119,6 +163,7 @@ function push_gs { push_gs_grav push_gs_cust + push_gs_cname push_gs_reload md5_recheck diff --git a/includes/gs-restore.sh b/includes/gs-restore.sh index bc56125..5870e35 100644 --- a/includes/gs-restore.sh +++ b/includes/gs-restore.sh @@ -13,6 +13,12 @@ function task_restore { show_target validate_gs_folders validate_ph_folders + + if [ "${INCLUDE_CNAME}" == "1" ] + then + validate_dns_folders + fi + validate_sqlite3 restore_gs @@ -65,10 +71,35 @@ function restore_gs { fi fi + if [ "$INCLUDE_CNAME" == '1' ] + then + + if [ -f ${DNSMAQ_DIR}/${CNAME_CONF} ] + then + ls ${LOCAL_FOLDR}/${BACKUP_FOLD} | grep $(date +%Y) | grep ${CNAME_CONF} | colrm 18 + + MESSAGE="Select backup date to restore ${CNAME_CONF} from" + echo_need + read INPUT_CNAMEBACKUP_DATE + + if [ -f ${LOCAL_FOLDR}/${BACKUP_FOLD}/${INPUT_CNAMEBACKUP_DATE}-${CNAME_CONF}.backup ] + then + MESSAGE="Backup File Selected" + else + MESSAGE="Invalid Request" + echo_info + + exit_nochange + fi + fi + fi + MESSAGE="${GRAVITY_FI} from ${INPUT_BACKUP_DATE} Selected" echo_info MESSAGE="${CUSTOM_DNS} from ${INPUT_DNSBACKUP_DATE} Selected" echo_info + MESSAGE="${CNAME_CONF} from ${INPUT_CNAMEBACKUP_DATE} Selected" + echo_info intent_validate @@ -173,6 +204,22 @@ function restore_gs { fi fi + if [ "$INCLUDE_CNAME" == '1' ] + then + if [ -f ${LOCAL_FOLDR}/${BACKUP_FOLD}/${INPUT_CNAMEBACKUP_DATE}-${CNAME_CONF}.backup ] + then + MESSAGE="Restoring ${CNAME_CONF} on $HOSTNAME" + echo_stat + sudo cp ${LOCAL_FOLDR}/${BACKUP_FOLD}/${INPUT_CNAMEBACKUP_DATE}-${CNAME_CONF}.backup ${DNSMAQ_DIR}/${CNAME_CONF} >/dev/null 2>&1 + error_validate + + MESSAGE="Validating Ownership on ${CNAME_CONF}" + echo_stat + + validate_cname_permissions + fi + fi + pull_gs_reload MESSAGE="Do you want to push the restored configuration to the primary Pi-hole? (yes/no)" diff --git a/includes/gs-smart.sh b/includes/gs-smart.sh index 65fa261..f8b7aa2 100644 --- a/includes/gs-smart.sh +++ b/includes/gs-smart.sh @@ -13,6 +13,12 @@ function task_smart { show_target validate_gs_folders validate_ph_folders + + if [ "${INCLUDE_CNAME}" == "1" ] + then + validate_dns_folders + fi + validate_sqlite3 validate_os_sshpass @@ -33,6 +39,8 @@ function smart_gs { SECDBCHANGE="0" PRICLCHANGE="0" SECCLCHANGE="0" + PRICNCHANGE="0" + SECCNCHANGE="0" if [ "${primaryDBMD5}" != "${last_primaryDBMD5}" ] then @@ -93,10 +101,8 @@ function smart_gs { if [ "$SKIP_CUSTOM" != '1' ] then - if [ -f "${PIHOLE_DIR}/${CUSTOM_DNS}" ] then - if [ "${PRICLCHANGE}" == "${SECCLCHANGE}" ] then if [ "${PRICLCHANGE}" != "0" ] @@ -139,6 +145,62 @@ function smart_gs { fi fi + if [ "${primaryCNMD5}" != "${last_primaryCNMD5}" ] + then + PRICNCHANGE="1" + fi + + if [ "${secondCNMD5}" != "${last_secondCNMD5}" ] + then + SECCNCHANGE="1" + fi + + if [ "$INCLUDE_CNAME" == "1" ] + then + if [ -f "${DNSMAQ_DIR}/${CNAME_CONF}" ] + then + if [ "${PRICNCHANGE}" == "${SECCNCHANGE}" ] + then + if [ "${PRICNCHANGE}" != "0" ] + then + MESSAGE="Both ${CNAME_CONF} Have Changed" + echo_warn + + PRICNDATE=$(${SSHPASSWORD} ${SSH_CMD} -p ${SSH_PORT} -i "$HOME/${SSH_PKIF}" ${REMOTE_USER}@${REMOTE_HOST} "stat -c %Y ${RNSMAQ_DIR}/${CNAME_CONF}") + SECCNDATE=$(stat -c %Y ${DNSMAQ_DIR}/${CNAME_CONF}) + + if (( "$PRICNDATE" >= "$SECCNDATE" )) + then + MESSAGE="Primary ${CNAME_CONF} Last Changed" + echo_warn + + pull_gs_cname + PULLRESTART="1" + else + MESSAGE="Secondary ${CNAME_CONF} Last Changed" + echo_warn + + push_gs_cname + PUSHRESTART="1" + fi + fi + else + if [ "${PRICNCHANGE}" != "0" ] + then + pull_gs_cname + PULLRESTART="1" + elif [ "${SECCNCHANGE}" != "0" ] + then + push_gs_cname + PUSHRESTART="1" + fi + fi + else + pull_gs_cname + PULLRESTART="1" + fi + fi + if [ "$PULLRESTART" == "1" ] then pull_gs_reload diff --git a/includes/gs-validate.sh b/includes/gs-validate.sh index 516f4b3..ba981ea 100644 --- a/includes/gs-validate.sh +++ b/includes/gs-validate.sh @@ -57,6 +57,20 @@ function validate_ph_folders { echo_good } +## Validate DNSMASQ Folders +function validate_dns_folders { + MESSAGE="Validating DNSMASQ Configuration" + echo_stat + + if [ ! -d ${DNSMAQ_DIR} ] + then + MESSAGE="Unable to Validate DNSMASQ Configuration Directory" + echo_fail + exit_nochange + fi + echo_good +} + ## Validate SQLite3 function validate_sqlite3 { MESSAGE="Validating SQLITE Installed on $HOSTNAME" @@ -158,4 +172,42 @@ function dbclient_warning { echo_warn fi fi +} + +## Validate CNAME Permissions +function validate_cname_permissions { + CNAMELS_OWN=$(ls -ld ${DNSMAQ_DIR}/${CNAME_CONF} | awk '{print $3 $4}') + if [ "$CNAMELS_OWN" == "rootroot" ] + then + echo_good + else + echo_fail + + MESSAGE="Attempting to Compensate" + echo_warn + + MESSAGE="Setting Ownership on ${CNAME_CONF}" + echo_stat + sudo chown root:root ${DNSMAQ_DIR}/${CNAME_CONF} >/dev/null 2>&1 + error_validate + fi + + MESSAGE="Validating Permissions on ${CNAME_CONF}" + echo_stat + + CNAMELS_RWE=$(namei -m ${DNSMAQ_DIR}/${CNAME_CONF} | grep -v f: | grep ${CNAME_CONF} | awk '{print $1}') + if [ "$CNAMELS_RWE" == "-rw-r--r--" ] + then + echo_good + else + echo_fail + + MESSAGE="Attempting to Compensate" + echo_warn + + MESSAGE="Setting Ownership on ${CNAME_CONF}" + echo_stat + sudo chmod 644 ${DNSMAQ_DIR}/${CNAME_CONF} >/dev/null 2>&1 + error_validate + fi } \ No newline at end of file