From 813a0ecd9810c7d3ab2de538e4c0837efa22094e Mon Sep 17 00:00:00 2001 From: Kieren <20251+Kieren@users.noreply.github.com> Date: Mon, 11 Jan 2021 17:57:39 +1030 Subject: [PATCH 1/3] Update syno_pihole.sh (#1) * Update syno_pihole.sh Initial (incomplete) commit for refining network configuration. * Remainder of initial re-working of networking logic and miscellainious changes. Untested commit. * Fixed check subnet code in validate_settings function. * Fixed prefix size comparison error in function is_cidr_in_subnet. * Added PARAM_HOST_IP check to validate_settings function. Fixed bug in function init_generated_values causing PARAM_HOST_IP not to be properly generated. * Fixed second bug in init_generated_values function - calling the int to ip conversion outside the appropriate conditional statement. * Fixed syntax error in function init_generated_values - comparison of variable integer equality. * Resolved final syntax error in function init_generated_values to make it functional. --- sample.env | 5 +- syno_pihole.sh | 243 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 162 insertions(+), 86 deletions(-) diff --git a/sample.env b/sample.env index e6a8407..ff3ae52 100644 --- a/sample.env +++ b/sample.env @@ -1,10 +1,11 @@ # Required network settings -PIHOLE_IP=192.168.0.250 # Static IP address of Pi-hole, ensure this IP is available and within your subnet +PIHOLE_IP=192.168.0.250 # Static IP address of Pi-hole, ensure this IP is available and within your network subnet # Optional network settings SUBNET=192.168.0.0/24 # Auto-detected on your Synology NAS if omitted GATEWAY=192.168.0.1 # Auto-detected on your Synology NAS if omitted -IP_RANGE=192.168.0.248/30 # Defaults to PIHOLE_IP/30 if omitted (four IPs is the minimum) +HOST_IP=192.168.0.249 # Defaults to first address not PIHOLE_IP starting at lowest address of IP_RANGE +IP_RANGE=192.168.0.248/30 # Defaults to PIHOLE_IP/32 if omitted VLAN_NAME=macvlan0 # Defaults to 'macvlan0' if omitted INTERFACE=eth0 # Auto-detected on your Synology NAS if omitted MAC_ADDRESS=70:d9:5a:70:99:cd # Unicast MAC address of Pi-hole, randomized if omitted diff --git a/syno_pihole.sh b/syno_pihole.sh index db39351..2204a25 100755 --- a/syno_pihole.sh +++ b/syno_pihole.sh @@ -36,6 +36,7 @@ NW_TIMEOUT=600 # timeout to wait for network response (in seconds) #====================================================================================================================== PARAM_PIHOLE_IP='' PARAM_SUBNET='' +PARAM_HOST_IP='' PARAM_GATEWAY='' PARAM_IP_RANGE='' PARAM_VLAN_NAME='' @@ -49,8 +50,6 @@ PARAM_DNS2='' PARAM_DATA_PATH='' PARAM_WEBPASSWORD='' PARAM_LOG_FILE='' -INFO_NETWORK_IP='' -INFO_BROADCAST_IP='' FORCE='false' LOG_PREFIX='' COMMAND='' @@ -76,29 +75,37 @@ usage() { echo "Usage: $0 [OPTIONS] COMMAND" echo echo "Options:" - echo " -f, --force Force update (bypass compatibility check and confirmation check)" - echo " -l, --log [LOG FILE] Display messages in log format, adding to [LOG FILE] if provided" + echo " -f, --force Force update (bypass compatibility check and confirmation check)." + echo " -l, --log [LOG FILE] Display messages in log format, adding to [LOG FILE] if provided." echo echo "Commands:" - echo " install [PARAMETERS] Install Pi-hole" - echo " network Create or recreate virtual network" - echo " update Update Pi-hole to latest version using existing settings" + echo " install (-i|--ip)
[PARAMETERS] Install Pi-hole." + echo " network (-i|--ip) [PARAMETERS] Create or recreate virtual network." + echo " update Update Pi-hole to latest version using " + echo " existing settings." echo - echo "Installation parameters:" - echo " -i, --ip Static IP address of Pi-hole (required)" - echo " -s, --subnet Subnet of the virtual network" - echo " -g, --gateway Gateway of the virtual network" - echo " -r, --range IP range with CIDR notation of the virtual network" - echo " -v, --vlan Name of the virtual network" - echo " -n, --interface Physical interface of the virtual network" - echo " -m, --mac Unicast MAC address" - echo " -d, --domain Fully qualified domain name" - echo " -H, --host Hostname of Pi-hole" - echo " -t, --timezone Timezone for Pi-hole" - echo " --DNS1 Primary DNS provider" - echo " --DNS2 Alternative DNS provider" - echo " --path Path where to store Pi-hole data" - echo " -p, --password Password for the Pi-hole admin" + echo "Parameters:" + echo " -d, --domain Container fully qualified domain name." + echo " --DNS1 Primary DNS provider." + echo " --DNS2 Alternative DNS provider." + echo " -g, --gateway Gateway of the LAN." + echo " -h, --help Print this usage guide and exit." + echo " -H, --host Hostname of Pi-hole." + echo " --host-ip Host IP address to communicate with Pi-hole container. Defaults" + echo " to the lowest address not the Pi-hole address (i) starting at" + echo " the first address of range (r). It's recommended to set this to" + echo " avoid possible collisions." + echo " -i, --ip (Required) static IP address of Pi-hole." + echo " -m, --mac Pi-hole container unicast MAC address" + echo " -n, --interface Physical interface to bind docker network to." + echo " -p, --password Password for the Pi-hole admin." + echo " --path Path where to store Pi-hole data." + echo " -r, --range IP range (CIDR notation) from local subnet. Designates the pool" + echo " of addresses reserved for containers attached to the generated" + echo " docker macvlan network. Range should not overlap LAN DHCP pool." + echo " -s, --subnet The LAN subnet to interface with." + echo " -t, --timezone Timezone for Pi-hole." + echo " -v, --vlan Name of the generated macvlan docker network." echo } @@ -163,9 +170,9 @@ is_valid_ip() { } # Returns 0 (successful) if an IPv4 address and routing suffix (CIDR format) comply with expected format -is_valid_cidr_network() { +is_valid_cidr() { local CIDR_REGEX='(((25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?))' - CIDR_REGEX+='(\/([8-9]|[1-2][0-9]|3[0-2]))([^0-9.]|$)' + CIDR_REGEX+='(\/([8-9]|[1-2][0-9]|3[0-2]))$' [[ $1 =~ ^$CIDR_REGEX$ ]] && return 0 || return 1 } @@ -178,26 +185,61 @@ is_valid_mac_address() { # Converts an IP address ($1) to an integer function convert_ip_to_int() { - local IFS_BACKUP="$IFS" - IFS=. read -r a b c d <<< "$1" + local IFS_BACKUP="$IFS" a b c d ip=$@ + IFS=. read -r a b c d <<< "$ip" echo "$((a * 256 ** 3 + b * 256 ** 2 + c * 256 + d))" IFS="$IFS_BACKUP" } +# Converts a decimal integer to a dotted IPv4 address +# https://stackoverflow.com/questions/10768160/ip-address-converter +function convert_int_to_ip() { + local ip dec=$@ + for e in {3..0} + do + ((octet = dec / (256 ** e) )) + ((dec -= octet * 256 ** e)) + ip+=$delim$octet + delim=. + done + echo "$ip" +} # Returns 0 if an IP address ($1) is in available CIDR range ($2), returns 1 otherwise # Assumes IP address and CIDR range are valid parameters -# Note: the network address and broadcast address are considered unavailable function is_ip_in_range() { - local IP=($1) - local IP_CIDR=($2) + local IP="$1" + local IP_CIDR="$2" local IP_INT=$(convert_ip_to_int "$IP") - local HOSTMIN=$(ipcalc -n "$IP_CIDR" | cut -f2 -d=) # network address is start of the range - local HOSTMAX=$(ipcalc -b "$IP_CIDR" | cut -f2 -d=) # broadcast address is end of the range - local HOSTMIN_INT=$(convert_ip_to_int "$HOSTMIN") - local HOSTMAX_INT=$(convert_ip_to_int "$HOSTMAX") + local CIDR_MIN_IP=$(ipcalc -n "$IP_CIDR" | cut -f2 -d=) # network address is start of the range + local CIDR_MAX_IP=$(ipcalc -b "$IP_CIDR" | cut -f2 -d=) # broadcast address is end of the range + local CIDR_MIN_IP_INT=$(convert_ip_to_int "$CIDR_MIN_IP") + local CIDR_MAX_IP_INT=$(convert_ip_to_int "$CIDR_MAX_IP") + + [ "$IP_INT" -ge "$CIDR_MIN_IP_INT" ] && [ "$IP_INT" -le "$CIDR_MAX_IP_INT" ] && return 0 || return 1 +} - [ "$IP_INT" -gt "$HOSTMIN_INT" ] && [ "$IP_INT" -lt "$HOSTMAX_INT" ] && return 0 || return 1 +# Returns 0 if CIDR range is a valid unicast address range of the subnet, returns 1 otherwise +# Assumes both arguments are are valid CIDR values +function is_cidr_in_subnet() { + local RANGE_CIDR="$1" + local SUBNET_CIDR="$2" + local RANGE_PREFIX_SIZE=$(echo "$RANGE_CIDR" | cut -d/ -f2) + local SUBNET_PREFIX_SIZE=$(echo "$SUBNET_CIDR" | cut -d/ -f2) + + # range prefix must be bigger than local subnets + [ $RANGE_PREFIX_SIZE -le $SUBNET_PREFIX_SIZE ] && return 1 + + # local broadcast address conflict? + local SUBNET_BCAST=$(ipcalc -b "$SUBNET_CIDR" | cut -f2 -d=) + local SUBNET_BCAST_INT=$(convert_ip_to_int "$SUBNET_BCAST_INT") + is_ip_in_range "$SUBNET_BCAST" "$RANGE_CIDR" + [ $? == 0 ] && return 1 + + # if a single range address is in the subnet then range is contained + local RANGE_IP=$(echo "$RANGE_CIDR" | cut -d/ -f1) + is_ip_in_range "$RANGE_IP" "$SUBNET_CIDR" + [ $? == 0 ] && return 0 || return 1 } # Detects available versions for Pi-hole @@ -234,6 +276,7 @@ init_env() { [ -z "$PARAM_SUBNET" ] && PARAM_SUBNET=${SUBNET} [ -z "$PARAM_GATEWAY" ] && PARAM_GATEWAY=${GATEWAY} [ -z "$PARAM_IP_RANGE" ] && PARAM_IP_RANGE=${IP_RANGE} + [ -z "$PARAM_HOST_IP" ] && PARAM_HOST_IP=${HOST_IP} [ -z "$PARAM_INTERFACE" ] && PARAM_INTERFACE=${INTERFACE} [ -z "$PARAM_MAC_ADDRESS" ] && PARAM_MAC_ADDRESS=${MAC_ADDRESS} [ -z "$PARAM_TIMEZONE" ] && PARAM_TIMEZONE=${TIMEZONE} @@ -248,8 +291,8 @@ init_env() { init_auto_detected_values() { # add auto-detected settings for omitted parameters if [ -z "$PARAM_SUBNET" ] ; then - HOST_IP=$(ip route list | grep "default" | awk '{print $7}') - PARAM_SUBNET=$(ip route list | grep "proto" | grep "$HOST_IP" | awk '{print $1}') + DEFAULT_HOST_IP=$(ip route list | grep "default" | awk '{print $7}') + PARAM_SUBNET=$(ip route list | grep "proto" | grep "$DEFAULT_HOST_IP" | awk '{print $1}') fi if [ -z "$PARAM_GATEWAY" ] ; then @@ -257,10 +300,8 @@ init_auto_detected_values() { fi if [ -z "$PARAM_IP_RANGE" ] && [ ! -z "$PARAM_PIHOLE_IP" ] ; then - # Find network address for minimum range containing Pi-hole IP (4 addresses) - # Note: the network address or broadcast address might clash with the Pi-hole IP (validate with is_ip_in_range) - local HOSTMIN=$(ipcalc -n "$PARAM_PIHOLE_IP/30" | cut -f2 -d=) # network address is start of the range - PARAM_IP_RANGE="$HOSTMIN/30" + # Reserve minimal range + PARAM_IP_RANGE="$PARAM_PIHOLE_IP/32" fi if [ -z "$PARAM_INTERFACE" ] ; then @@ -277,12 +318,20 @@ init_auto_detected_values() { PARAM_TIMEZONE=$(find /usr/share/zoneinfo/ -type f -exec sh -c "diff -q /etc/localtime '{}' \ > /dev/null && echo {}" \; | sed 's|/usr/share/zoneinfo/||g') fi +} + +# generate any required omitted parameters +init_generated_values() { + # host macvlan bridge ip + if [ -z "$PARAM_HOST_IP" ] ; then + local ip=$(ipcalc -n "$PARAM_IP_RANGE" | cut -f2 -d=) + local ip_int=$(convert_ip_to_int "$ip") + local ph_int=$(convert_ip_to_int "$PARAM_PIHOLE_IP") - # initialize informational parameters - is_valid_cidr_network "$PARAM_IP_RANGE" - if [ $? == 0 ] ; then - INFO_NETWORK_IP=$(ipcalc -n "$PARAM_IP_RANGE" | cut -f2 -d=) # network address of the range - INFO_BROADCAST_IP=$(ipcalc -b "$PARAM_IP_RANGE" | cut -f2 -d=) # broadcast address of the range + if [ $ip_int == $ph_int ] ; then + $((ip_int++)) + fi + PARAM_HOST_IP=$(convert_int_to_ip "$ip_int") fi } @@ -299,27 +348,46 @@ safe_replace_in_file() { # Validate parameter settings validate_settings() { local INVALID_SETTINGS="" + local WARNING_SETTINGS="" - # validate mandatory parameters conform to expected value - is_valid_ip "$PARAM_PIHOLE_IP" - [ $? == 1 ] && terminate "No valid IP address provided" - + # # validate parameters conform to expected value - is_valid_ip "$PARAM_PIHOLE_IP" - [ $? == 1 ] && INVALID_SETTINGS+="Invalid Pi-hole IP: ${PARAM_PIHOLE_IP}\n" + # - is_valid_cidr_network "$PARAM_SUBNET" + # -- IP parameters -- + # Check the subnet first, this is the (L3) network we intend to interface with. + + is_valid_cidr "$PARAM_SUBNET" [ $? == 1 ] && INVALID_SETTINGS+="Invalid subnet: ${PARAM_SUBNET}\n" is_valid_ip "$PARAM_GATEWAY" [ $? == 1 ] && INVALID_SETTINGS+="Invalid gateway: ${PARAM_GATEWAY}\n" + is_cidr_in_subnet "$PARAM_GATEWAY/32" "$PARAM_SUBNET" + [ $? == 1 ] && INVALID_SETTINGS+="Gateway address '$PARAM_GATEWAY' is not in subnet: '$PARAM_SUBNET'\n" + + # A valid docker network range should be contained by the local subnet. + # The IP range designates a pool of IP addresses that docker allocates (by default) to containers + # attached to the docker network. + # This script defines Pi-hole a static IP address and only requires it be valid in the subnet, + # the user is free to pass their own valid address outside the range. + is_valid_ip "$PARAM_PIHOLE_IP" + [ $? == 1 ] && INVALID_SETTINGS+="Invalid Pi-hole IP: ${PARAM_PIHOLE_IP}\n" + is_cidr_in_subnet "$PARAM_PIHOLE_IP/32" "$PARAM_SUBNET" + [ $? == 1 ] && INVALID_SETTINGS+="Pi-hole IP address '$PARAM_PIHOLE_IP' is not valid in subnet '$PARAM_SUBNET\n" - is_valid_cidr_network "$PARAM_IP_RANGE" + is_valid_ip "$PARAM_HOST_IP" + [ $? == 1 ] && INVALID_SETTINGS+="Invalid Host IP: ${PARAM_HOST_IP}\n" + is_cidr_in_subnet "$PARAM_HOST_IP/32" "$PARAM_SUBNET" + [ $? == 1 ] && INVALID_SETTINGS+="Host IP address '$PARAM_HOST_IP' is not valid in subnet '$PARAM_SUBNET\n" + + is_valid_cidr "$PARAM_IP_RANGE" [ $? == 1 ] && INVALID_SETTINGS+="Invalid IP range: ${PARAM_IP_RANGE}\n" + is_cidr_in_subnet "$PARAM_IP_RANGE" "$PARAM_SUBNET" + [ $? == 1 ] && INVALID_SETTINGS+="Docker network IP address range is not in subnet '$PARAM_SUBNET'\n" is_ip_in_range "$PARAM_PIHOLE_IP" "$PARAM_IP_RANGE" - [ $? == 1 ] && INVALID_SETTINGS+="IP '$PARAM_PIHOLE_IP' not available in range '$PARAM_IP_RANGE'\n" - + [ $? == 1 ] && WARNING_SETTINGS+="IP '$PARAM_PIHOLE_IP' not in docker network range '$PARAM_IP_RANGE'\n" + is_valid_mac_address "$PARAM_MAC_ADDRESS" [ $? == 1 ] && INVALID_SETTINGS+="Invalid MAC address: ${PARAM_MAC_ADDRESS}\n" @@ -335,6 +403,8 @@ validate_settings() { if [ "$INVALID_SETTINGS" ] ; then log "$INVALID_SETTINGS" terminate "Invalid parameters" + elif [ "$WARNING_SETTINGS" ] ; then + log "$WARNING_SETTINGS" fi } @@ -412,23 +482,23 @@ define_pihole_versions() { init_settings() { print_status "Initializing network and Pi-hole settings" init_auto_detected_values + init_generated_values validate_settings - log "Pi-hole IP: $PARAM_PIHOLE_IP" - log "Subnet: $PARAM_SUBNET" - log "Gateway: $PARAM_GATEWAY" - log "IP range: $PARAM_IP_RANGE" - log "Network IP: $INFO_NETWORK_IP" - log "Broadcast IP: $INFO_BROADCAST_IP" - log "VLAN: $PARAM_VLAN_NAME" - log "Interface: $PARAM_INTERFACE" - log "MAC address: $PARAM_MAC_ADDRESS" - log "Domain name: $PARAM_DOMAIN_NAME" - log "Hostname: $PARAM_PIHOLE_HOSTNAME" - log "Timezone: $PARAM_TIMEZONE" - log "DNS1: $PARAM_DNS1" - log "DNS2: $PARAM_DNS2" - log "Data path: $PARAM_DATA_PATH" + log "Interface: $PARAM_INTERFACE" + log "Subnet: $PARAM_SUBNET" + log "Gateway: $PARAM_GATEWAY" + log "Host IP address: $PARAM_HOST_IP" + log "VLAN: $PARAM_VLAN_NAME" + log "Pi-hole MAC address: $PARAM_MAC_ADDRESS" + log "Pi-hole IP address: $PARAM_PIHOLE_IP" + log "Docker network IP range: $PARAM_IP_RANGE" + log "Domain name: $PARAM_DOMAIN_NAME" + log "Hostname: $PARAM_PIHOLE_HOSTNAME" + log "Timezone: $PARAM_TIMEZONE" + log "DNS1: $PARAM_DNS1" + log "DNS2: $PARAM_DNS2" + log "Data path: $PARAM_DATA_PATH" if [ -z "$PARAM_WEBPASSWORD" ] ; then log "Web password: (not set)" else @@ -558,28 +628,28 @@ execute_wait_for_network() { # Create macvlan interface execute_create_macvlan() { - print_status "Creating network interface" + print_status "Creating interface to bridge host and docker network" - local STATUS + local STATUS="" - # (re-)create macvlan bridge network attached to the physical interface + # (re-)create macvlan bridge attached to the network interface STATUS=$(ip link | grep "$PARAM_VLAN_NAME") - if [ "$STATUS" ] ; then + if [ -z "$STATUS" ] ; then log "Removing existing link '$PARAM_VLAN_NAME'" ip link set "$PARAM_VLAN_NAME" down > /dev/null 2>&1 ip link delete "$PARAM_VLAN_NAME" > /dev/null 2>&1 fi - log "Adding link '$PARAM_VLAN_NAME' for macvlan in bridge mode" + log "Adding macvlan interface '$PARAM_VLAN_NAME' " ip link add "$PARAM_VLAN_NAME" link "$PARAM_INTERFACE" type macvlan mode bridge - # reserve part of the interface scope for macvlan + # assign host address to macvlan STATUS=$(ip addr | grep "$PARAM_VLAN_NAME") if [ -z "$STATUS" ] ; then - log "Allocating IP range '$PARAM_IP_RANGE' to '$PARAM_VLAN_NAME'" - ip addr add "$PARAM_IP_RANGE" dev "$PARAM_VLAN_NAME" > /dev/null 2>&1 - else - log "Updating current IP range of '$PARAM_VLAN_NAME' to '$PARAM_IP_RANGE'" - ip addr change "$PARAM_IP_RANGE" dev "$PARAM_VLAN_NAME" > /dev/null 2>&1 + log "Assign IP address '$PARAM_HOST_IP' to '$PARAM_VLAN_NAME'" + ip addr add "$PARAM_HOST_IP/32" dev "$PARAM_VLAN_NAME" > /dev/null 2>&1 + else # this should never happen because link is deleted above if exists + log "Updating current IP address of '$PARAM_VLAN_NAME' to '$PARAM_HOST_IP'" + ip addr change "$PARAM_HOST_IP/32" dev "$PARAM_VLAN_NAME" > /dev/null 2>&1 fi # bring macvlan interface up @@ -708,7 +778,7 @@ while [ "$1" != "" ]; do -s | --subnet ) shift PARAM_SUBNET="$1" - is_valid_cidr_network "$PARAM_SUBNET" + is_valid_cidr "$PARAM_SUBNET" [ $? == 1 ] && terminate "Invalid subnet" ;; -g | --gateway ) @@ -720,7 +790,7 @@ while [ "$1" != "" ]; do -r | --range ) shift PARAM_IP_RANGE="$1" - is_valid_cidr_network "$PARAM_IP_RANGE" + is_valid_cidr "$PARAM_IP_RANGE" [ $? == 1 ] && terminate "Invalid IP range" ;; -v | --vlan ) @@ -771,6 +841,10 @@ while [ "$1" != "" ]; do shift PARAM_WEBPASSWORD="$1" ;; + --host-ip ) + shift + PARAM_HOST_IP="$1" + ;; install | network | update ) COMMAND="$1" ;; @@ -818,4 +892,5 @@ case "$COMMAND" in terminate "No command specified" esac -log "Done." \ No newline at end of file +log "Done." + From ac7f0eaaef8258a44570a55135529614d211291c Mon Sep 17 00:00:00 2001 From: Kieren <20251+Kieren@users.noreply.github.com> Date: Tue, 12 Jan 2021 13:58:51 +1030 Subject: [PATCH 2/3] Fix bug in define_pihole_versions which detects wrong version. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thus 'update' pihole function doesn't work as intended. Pihole lists three version numbers for the core components of Pi-hole: Pi-hole (core?), AdminFTE and FTL. However they have one release number tagged in the repository. Rather than issuing a single release number for the whole project this tagged release number seems to track the version number of which ever of the three core components is highest. This fix is just as fragile as the code it is fixing – it simply changes the component number it checks from Pi-hole to FTL. The Repository currently states FTL is expected to be the highest version number going forward, so this fragile version detection may well work for a while going forward, however it should really be more rigorous or perhaps an issue raised with Pi-hole project. --- syno_pihole.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/syno_pihole.sh b/syno_pihole.sh index db39351..4ebae45 100755 --- a/syno_pihole.sh +++ b/syno_pihole.sh @@ -152,8 +152,8 @@ is_valid_log_file() { # Returns 0 (successful) if version string complies with expected format is_valid_version() { - local IP_VERSION='([0-9]+\.)?([0-9]+\.)?(\*|[0-9]+)' - [[ $1 =~ ^$IP_VERSION$ ]] && return 0 || return 1 + local IP_VERSION='^([0-9]+\.)?([0-9]+\.)?(\*|[0-9]+)$' + [[ $1 =~ $IP_VERSION ]] && return 0 || return 1 } # Returns 0 (successful) if an IPv4 address complies with expected format @@ -203,6 +203,7 @@ function is_ip_in_range() { # Detects available versions for Pi-hole detect_available_versions() { # Detect latest available stable Pi-hole version (ignores release candidates) + # Repository has stated FTL is the leading developement release version listed as latest. if [ -z "$TARGET_PIHOLE_VERSION" ] ; then TARGET_PIHOLE_VERSION=$(curl -s "$GITHUB_API_PIHOLE" | grep "tag_name" | egrep -o "[0-9]+.[0-9]+.[0-9]+") @@ -389,7 +390,8 @@ define_pihole_versions() { print_status "Detecting current and available Pi-hole versions" # Detect current Pi-hole version (should comply with 'version.release.modification') - PIHOLE_VERSION=$(docker exec -it "$PIHOLE_CONTAINER" pihole -v 2>/dev/null | grep 'Pi-hole' | awk '{print $4}' \ + # Repository has stated FTL is the leading developement release version listed as latest. + PIHOLE_VERSION=$(docker exec "$PIHOLE_CONTAINER" pihole -v 2>/dev/null | grep 'FTL' | awk '{print $4}' \ | cut -c2-) is_valid_version "$PIHOLE_VERSION" [ $? == 1 ] && PIHOLE_VERSION='' From e8d55cce8713a233cc59143b7b4e17c949b082d2 Mon Sep 17 00:00:00 2001 From: Kieren <20251+Kieren@users.noreply.github.com> Date: Sat, 16 Jan 2021 16:44:59 +1030 Subject: [PATCH 3/3] Update README.md inline with patch Updated the readme to better reflect the changes made to the script in this patch. Particularly adding the new optional --host-ip parameter. --- README.md | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 985acbe..dec6cd7 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ cd synology-pihole ## Usage *Synology-pihole* requires `sudo` rights. Use the following command to invoke *synology-pihole* from the command line. -```console +``` sudo ./syno_pihole.sh [OPTIONS] [PARAMETERS] COMMAND ``` @@ -101,7 +101,7 @@ sudo ./syno_pihole.sh update | **`network`** | Creates or recreates virtual network | | **`update`** | Updates an existing Pi-hole Docker container | -In the addition, the following options are available. +In addition, the following options are available. | Option | Alias | Parameter | Description | |--------|------------|------------|-------------| @@ -114,19 +114,20 @@ In the addition, the following options are available. | Variable | Parameter | Required | Example | Description | |-------------------|-----------------|----------|----------------------|-------------| | `PIHOLE_IP` | -i, --ip | `Yes` | `192.168.0.250` | Static IP address of Pi-hole, ensure this IP address is available | -| `SUBNET` | -s, --subnet | `No` | `192.168.0.0/24` | Subnet of the virtual network for Pi-hole (auto-detected if omitted) | -| `GATEWAY` | -g, --gateway | `No` | `192.168.0.1` | Gateway of the virtual network for Pi-hole (auto-detected if omitted) | -| `IP_RANGE` | -r, --range | `No` | `192.168.0.250/30` | IP range with CIDR notation of the virtual network for Pi-hole (defaults to `PIHOLE_IP/30`) | -| `VLAN_NAME` | -v, --vlan | `No` | `macvlan0` | Name of the virtual network for Pi-hole (defaults to `macvlan0`) | -| `INTERFACE` | -n, --interface | `No` | `eth0` | Physical interface of the virtual network for Pi-hole (auto-detected if omitted) | -| `MAC_ADDRESS` | -m, --mac | `No` | `70:d9:5a:70:99:cd` | Unicast MAC address of Pi-hole (randomized if omitted) | -| `DOMAIN_NAME` | -d, --domain | `No` | `pihole.example.com` | Fully qualified domain name for Pi-hole | -| `PIHOLE_HOSTNAME` | -H, --host | `No` | `pihole` | Hostname of Pi-hole (defaults to `pihole`) | -| `TIMEZONE` | -t, --timezone | `No` | `Europe/Amsterdam` | Timezone for Pi-hole (see [Wikipedia][timezone_list] for an overview, auto-detected if omitted) | +| `INTERFACE` | -n, --interface | `No` | `eth0` | Host network interface to the subnet, auto-detected if omitted | +| `SUBNET` | -s, --subnet | `No` | `192.168.0.0/24` | CIDR notated subnet the Pi-Hole will join, auto-detected if omitted | +| `GATEWAY` | -g, --gateway | `No` | `192.168.0.1` | Subnet gateway router address (see --subnet), auto-detected if omitted | +| `HOST_IP` | --host-ip | `No` | `192.168.0.3` | New host address for communicating with Pi-hole via macvlan bridge interface. By default the lowest address starting at the first (not the Pi-hole address) of the Docker network range (see --range) is used | +| `IP_RANGE` | -r, --range | `No` | `192.168.0.250/30` | CIDR notated address range for Docker to assign to containers attached to the created 'Docker macvlan Network', defaults to `PIHOLE_IP/32` | +| `VLAN_NAME` | -v, --vlan | `No` | `macvlan0` | Name assigned to the generated macvlan interface on the host to enable container <-> host communication (defaults to `macvlan0`) | +| `MAC_ADDRESS` | -m, --mac | `No` | `70:d9:5a:70:99:cd` | Unicast MAC to assign Pi-hole, randomized if omitted | +| `DOMAIN_NAME` | -d, --domain | `No` | `example.com` | Fully qualified domain of the subnet | +| `PIHOLE_HOSTNAME` | -H, --host | `No` | `pihole` | Hostname of Pi-hole, defaults to `pihole` | +| `TIMEZONE` | -t, --timezone | `No` | `Europe/Amsterdam` | Local Timezone (see [Wikipedia][timezone_list] for an overview, auto-detected if omitted) | | `DNS1` | --DNS1 | `No` | `1.1.1.1` | Primary DNS provider to be used by Pi-hole (see this [list][upstream_dns] for typical providers) | | `DNS2` | --DNS2 | `No` | `1.0.0.1` | Alternative DNS provider to be used by Pi-hole | -| `DATA_PATH` | --path | `No` | `./data` | Path where to store your Pi-hole data (defaults to `./data`) | -| `WEBPASSWORD` | -p, --password | `No` | `password` | Password for the Pi-hole admin (prompted for when omitted) | +| `DATA_PATH` | --path | `No` | `./data` | Host data location path for Pi-hole, defaults to `./data` | +| `WEBPASSWORD` | -p, --password | `No` | `password` | Password for the Pi-hole administrative web interface (prompted for when omitted) | ### Scheduled Tasks #### Updating Pi-Hole to the Latest Version @@ -139,10 +140,10 @@ It is recommended to schedule a task to ensure Pi-hole uses the latest version /bin/sh /path/to/your/script/syno_pihole.sh update -l /var/log/syno_pihole.log ``` -#### Ensuring the Virtual Network is Available After Reboot -By default, Docker containers are automatically restarted after a system reboot. However, the virtual network setup by `synology-pihole` is lost after a system reboot and/or update. Similar to the instructions in the previous paragraph, you can setup a task to automatically recreate the virtual network during the boot process of your Synology NAS. Follow these steps to do so. +#### Ensuring the Host <-> Container Bridge Interface is Available After Reboot +By default, Docker containers are automatically restarted after a system reboot. However, the macvlan bridge interface setup by `synology-pihole` is lost after a system reboot and/or update. Similar to the instructions in the previous paragraph, you can setup a task to automatically recreate it during the boot process of your Synology NAS. Follow these steps to do so. 1. Access `Task Scheduler` via `Control Panel ➡ Task Scheduler` in DSM. -2. Now click on `Create ➡ Triggered Task ➡ User-defined script` to create a custom script. Give the task a familiar name in the tab `General`, such as `Recreate Pi-hole network`. +2. Now click on `Create ➡ Triggered Task ➡ User-defined script` to create a custom script. Give the task a familiar name in the tab `General`, such as `Recreate Pi-hole Bridge Interface`. 3. In the same screen, select `root` as user and `Boot-up` as event. 4. Finally, enter the following script in the user-defined script section of the `Task Settings` tab. Be sure to update `/path/to/your/script/`. The optional instruction `-l /var/log/syno_pihole.log` copies all messages to a log file. The option `--force` is required to avoid the script asking for user confirmation. ```console @@ -150,7 +151,7 @@ By default, Docker containers are automatically restarted after a system reboot. ``` ### Configuration -The Pi-hole [FAQ][pihole_dns] describes various options on how to configure Pi-hole as DNS server. The portal of Pi-hole is available by navigating to `http://ip_address/admin/` (replacing `ip_address` with the correct IP address). +The Pi-hole [FAQ][pihole_dns] describes various options on how to configure the Pi-hole DNS server. The Pi-hole administor web interface is available by navigating to `http://ip_address/admin/` (replacing `ip_address` with the correct IP address). ## Contributing @@ -203,4 +204,4 @@ Copyright © [Mark Dumay][blog] [blog]: https://markdumay.com --> [blog]: https://github.com/markdumay -[repository]: https://github.com/markdumay/synology-pihole.git \ No newline at end of file +[repository]: https://github.com/markdumay/synology-pihole.git