NAS-Script: Firewall toegang o.b.v. DDNS-hostname

Status: Dit is de laatste versie van dit script.

Beschrijving

De standaard firewall in een Synology NAS geeft enkel de mogelijkheid voor het whitelisten (of blacklisten) op basis van een IP-adres. Maar stel nou dat het IP-adres wijzigt omdat je internetprovider dat nou eenmaal zo nu en dan doet? De toegang vanaf dat IP-adres is dan direct geblokkeerd, en inloggen of het runnen van een backup is dan niet meer mogelijk.

Om dit te voorkomen heb ik een script geschreven om de toegang op basis van een DDNS-hostname te controleren, en in geval van een wijziging van het IP-adres automatisch te corrigeren in de firewall.

Code

# Steenderen.NET
# NAS-script: Check access for hostname - Versie 1.0
# Dependency: PHP8.2 must be installed.

IFS="`printf '\n\t'`"

# Setup
ACCESS_FOR_HOSTNAME="myname.ddns-provider.net"
NETWORK_INTERFACE="1"
# Default 1 if firewall was set on All interfaces or specificall on LAN1 interface, use 2 only if LAN 2 interface is used. 

MAIL_FROM="mail@provider.com"
MAIL_TO="mail@provider.com"
MAIL_HOSTNAME="Hostname"
MAIL_OLD_IP="Laatst bekende IP-adres"
MAIL_FOUND_IP="Nieuw gevonden IP-adres"
MAIL_SUBJECT_NO_LOOKUP="DNS-lookup mislukt voor opgegeven hostname"
MAIL_BODY_NO_LOOKUP_START="Beste gebruiker,\n\nDe DNS-lookup voor onderstaande hostname is mislukt."
MAIL_BODY_NO_LOOKUP_END="Het gekoppelde IP-adres kon hierdoor niet worden gecontroleerd in de firewall voor toegang tot deze NAS."
MAIL_SUBJECT_LAST_KNOWN_IP_NOT_FOUND="Laatst bekende IP-adres onbekend in firewall configuratie"
MAIL_BODY_LAST_KNOWN_IP_NOT_FOUND_START="Beste gebruiker,\n\nHet laatst bekende IP-adres voor toegang tot deze NAS is onbekend in de firewall configuratie."
MAIL_BODY_LAST_KNOWN_IP_NOT_FOUND_END="Controleer de configuratie en voeg het nieuw gevonden IP-adres handmatig toe voor toegang tot deze NAS."
MAIL_SUBJECT_IP_CHANGED="IP-adres automatisch gewijzigd in firewall configuratie"
MAIL_BODY_IP_CHANGED_START="Beste gebruiker,\n\nEr is een wijziging geconstateerd voor het IP-adres behorende bij onderstaande hostname."
MAIL_BODY_IP_CHANGED_END="Deze wijziging is automatisch verwerkt in de firewall configuratie, het nieuw gevonden IP-adres heeft (weer) toegang tot deze NAS."
MAIL_SIGNATURE="Met vriendelijke groeten,\nSynology DiskStation"

# No need to edit below here.
echo "Start running check access for hostname script."

# Get directory where script is run from
CURRENT_DIR=$(cd `dirname $0` && pwd)

# DNS-lookup to resolve IP address for given hostname
HOST_IP_ADDRESS="$(ping -q -c 1 -t 1 $ACCESS_FOR_HOSTNAME | grep PING | sed -e 's/).*//' | sed -e 's/.*(//')"

# If DNS-lookup failed
if [ -z "$HOST_IP_ADDRESS" ]; then
	php82 -r 'mail("'$MAIL_TO'", "'$MAIL_SUBJECT_NO_LOOKUP'", "'$MAIL_BODY_NO_LOOKUP_START'\n\n'$MAIL_HOSTNAME': '$ACCESS_FOR_HOSTNAME'\n\n'$MAIL_BODY_NO_LOOKUP_END'\n\n'$MAIL_SIGNATURE'", "From: '$MAIL_FROM'");';
	echo "- Hostname not found at DNS-lookup for $ACCESS_FOR_HOSTNAME, warning e-mail was sent."
	/usr/syno/bin/synologset1 sys info 0x11100000 "Check access for hostname: Hostname not found at DNS-lookup for $ACCESS_FOR_HOSTNAME, warning e-mail was sent.";

# If DNS-lookup was successful
else
	IP_FILE_NAME="check_access_for_$ACCESS_FOR_HOSTNAME.txt"

	# The last known IP address for the given hostname is stored in check_access_for_hostname.txt.
	# Check if check_access_for_hostname.txt already exists, if not create it for the first time.

	if [[ ! -f "$CURRENT_DIR/$IP_FILE_NAME" ]]; then
		echo "- File $CURRENT_DIR/$IP_FILE_NAME does not exist."
		echo $HOST_IP_ADDRESS > $CURRENT_DIR/$IP_FILE_NAME
		echo "- IP address found for "$ACCESS_FOR_HOSTNAME" is "$HOST_IP_ADDRESS" and now for first time stored in $CURRENT_DIR/$IP_FILE_NAME to compare to the next time."
		/usr/syno/bin/synologset1 sys info 0x11100000 "Check access for hostname: IP address found for $ACCESS_FOR_HOSTNAME is "$HOST_IP_ADDRESS" and now for first time stored in "$CURRENT_DIR"/"$IP_FILE_NAME" to compare to next time";

	# If check_access_for_hostname.txt does exist, compare stored IP address with found IP address.
	else
		echo "- IP address found for $ACCESS_FOR_HOSTNAME is $HOST_IP_ADDRESS."

		LAST_IP_ADDRESS="$(cat $CURRENT_DIR/$IP_FILE_NAME)"
		echo "- Last known IP address for $ACCESS_FOR_HOSTNAME was $LAST_IP_ADDRESS, as found in $CURRENT_DIR/$IP_FILE_NAME"

		# Check if found IP address is still the same as the stored IP address.
		if [[ "$HOST_IP_ADDRESS" == "$LAST_IP_ADDRESS" ]]; then
			echo "- IP address for $ACCESS_FOR_HOSTNAME was not changed, no further action taken."
			/usr/syno/bin/synologset1 sys info 0x11100000 "Check access for hostname: IP address "$LAST_IP_ADDRESS" for "$ACCESS_FOR_HOSTNAME" was not changed, no further action taken";
		else
			# If the found IP address was changed, check if the last known IP address can be found in the firewall configuration.
			if grep -q $LAST_IP_ADDRESS "/usr/syno/etc/firewall.d/"$NETWORK_INTERFACE".json"; then
				# Change IP address in firewall configuration from last known IP address to newly resolved IP address.
				sed -i 's/'$LAST_IP_ADDRESS'/'$HOST_IP_ADDRESS'/g' /usr/syno/etc/firewall.d/$NETWORK_INTERFACE.json
				echo "- Changed $LAST_IP_ADDRESS to $HOST_IP_ADDRESS in firewall configuration."

				/usr/syno/bin/synofirewall --reload
				echo "- Reloaded firewall configuration."

				if grep -q $HOST_IP_ADDRESS "/usr/syno/etc/firewall.d/"$NETWORK_INTERFACE".json"; then
					echo "- Checked firewall configuration and new IP address was found correctly."

					echo $HOST_IP_ADDRESS > $CURRENT_DIR/$IP_FILE_NAME
					echo "- New IP address stored in check_access_for_hostname.txt to compare to next time."

					php82 -r 'mail("'$MAIL_TO'", "'$MAIL_SUBJECT_IP_CHANGED'", "'$MAIL_BODY_IP_CHANGED_START'\n\n'$MAIL_HOSTNAME': '$ACCESS_FOR_HOSTNAME'\n'$MAIL_OLD_IP': '$LAST_IP_ADDRESS'\n'$MAIL_FOUND_IP': '$HOST_IP_ADDRESS'\n\n'$MAIL_BODY_IP_CHANGED_END'\n\n'$MAIL_SIGNATURE'", "From: '$MAIL_FROM'");';
					echo "- Notification e-mail was sent."
					/usr/syno/bin/synologset1 sys info 0x11100000 "Check access for hostname: Last known IP address was replace for new IP address in firewall configuration, notification e-mail was sent.";
				else
					echo "- Check firewall configuration but new IP address was NOT found, no further action taken."
				fi
			else
				php82 -r 'mail("'$MAIL_TO'", "'$MAIL_SUBJECT_LAST_KNOWN_IP_NOT_FOUND'", "'$MAIL_BODY_LAST_KNOWN_IP_NOT_FOUND_START'\n\n'$MAIL_HOSTNAME': '$ACCESS_FOR_HOSTNAME'\n'$MAIL_FOUND_IP': '$HOST_IP_ADDRESS'\n\n'$MAIL_BODY_LAST_KNOWN_IP_NOT_FOUND_END'\n\n'$MAIL_SIGNATURE'", "From: '$MAIL_FROM'");';
				echo "- Last known IP address was not found in firewall configuration, so could not be replaced with new IP address, warning e-mail was sent."
				/usr/syno/bin/synologset1 sys info 0x11100000 "Last known IP address was not found in firewall configuration, so could not be replaced with new IP address, warning e-mail was sent.";
			fi
		fi
	fi
fi

# Done!
echo "Done running check access for hostname script."

Installatie-instructies

DDNS instellen

Om te beginnen is het belangrijk om een DDNS-hostname in te stellen voor het IP-adres dat je toegang wilt geven toe jouw NAS.

Als deze locatie ook beschikt over een Synology NAS, dan biedt Synology de mogelijkheid om onder Configuratiescherm > Externe toegang > DDNS (tabje) dit in te stellen. Synology biedt hiervoor een gratis dienst aan, waarmee de NAS jouw IP adres kan koppelen aan een zelf te kiezen hostname, bijvoorbeeld mijnnaam.synology.net. Deze hostname gebruik je later bij het instellen van het script.

Er zijn ook andere mogelijkheden, bijvoorbeeld via een Raspberry Pi, of ander type NAS. Zolang je maar een DDNS-hostname beschikbaar hebt voor het IP-adres dat je toegang wilt verlenen.

Firewall instellen

Voor de eerste keer toegang verlenen is het nodig dat je handmatig het IP-adres configureert in de Synology firewall en tot welke diensten (poorten) dit adres toegang moet krijgen. Dit is éénmalig handmatig, daarna neemt het scripts verdere aanpassingen voor z’n rekening.

Script gebruiken

Sla het script op in een nieuw bestand met de naamgeving check_access_for_hostname.sh. Op dezelfde locatie wordt bij de eerste keer uitvoeren van het script een txt-bestand aangemaakt in de vorm van check_access_for_hostname.txt.

Vul in het script, onder #Setup, ten minste de eerste vier variabelen in m.b.t. de DDNS-hostname, de netwerk-interface, en de te verzenden notificatie e-mail.

Plan het script in om dagelijks te draaien via de Taakplanner in het Configuratiescherm van je NAS met root-rechten. Mijn ervaring is dat één keer per dag eigenlijk voldoende is, maar vaker mag natuurlijk. Ik heb zelf in de planning rekening gehouden met het tijdstip waarop een backup staat ingepland. Door dit script voorafgaand hieraan te laten draaien, borg ik dat een backup niet mislukt door een gewijzigd IP-adres.

Let er bij het inplannen op dat je het volledige pad gebruikt naar de locatie waar je het script het opgeslagen, dit is bijvoorbeeld /volume1/beheer/check_access_for_hostname.sh

Opmerkingen

Mocht je meerdere ip-adressen whitelisten in je firewall, en zijn die adressen gekoppeld aan een DDNS-hostname, dan kan je prima voor iedere hostname een eigen versie van dit script schedulen. In dat geval is het handig om in de bestandsnaam hostname te vervangen voor een meer leesbare / herkenbare naam voor die hostname.

Geef een reactie

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Deze site gebruikt Akismet om spam te verminderen. Bekijk hoe je reactie gegevens worden verwerkt.