#!/bin/sh

# DynamicIPv6Aliases v1.2
# 
# Detects a changing IPv6 network/prefix (inet6 autoconf)
# and lets you react to it. It is meant for private Internet
# connections where the networkaddress/prefix changes regularly.
# Written for OpenBSD.

# # crontab -l
# ...
# * * * * * /etc/IPv6Aliases.sh re0

interface=$1

change() {
	newIPv6Net=$1
	oldIPv6Net=$2
	echo New: $newIPv6Net
	echo Old: $oldIPv6Net
	
	# Enter individual reactions here:
	# Examples
	# Email
	ifconfig $interface inet6 alias $newIPv6Net:1:2:3:4
	
	echo "v6adr = $newIPv6Net:1:2:3:4" > /etc/mail/v6adr
	rcctl restart smtpd
	
	# Update DynDNS
	ftp -o /dev/null "https://user:pass@dyndns.example.com/nic/update?myipv6=$newIPv6Net:1:2:3:4" > /dev/null
	
	
	# Web
	ifconfig $interface inet6 alias $newIPv6Net:a:b:c:d
	
	cp /etc/httpd.conf /etc/httpd.conf-ov6
	cat /etc/httpd.conf-ov6 \
	    | sed "s/Nv6adr\ \=.*/Nv6adr\ \=\ $newIPv6Net:a:b:c:d/g" \
	    > /etc/httpd.conf
	
	rcctl check httpd > /dev/null
	if [ $? -eq 0 ]; then
		rcctl reload httpd
	else
		rcctl restart httpd
	fi
	
	
	# Delete old addresses.
	if [ "$oldIPv6Net" != "" ]
	then
		# Email
		ifconfig $interface inet6 delete $oldIPv6Net:1:2:3:4
		# Web
		ifconfig $interface inet6 delete $oldIPv6Net:a:b:c:d
	fi
	
	# End of individual reaction!
}


[ "$interface" == "" ] && ( echo Usage: $0 network-interface; exit )

# Wait till the system has at least two minutes of uptime.
uptime=`echo $(( $(date +%s) - $(sysctl -n kern.boottime) ))`
[ $uptime -lt 120 ] && exit

# route -n show -inet6 | grep $interface = List all IPv6 networks.
# grep ::/64 = List only network addresses.
# grep -vE '^(fc|fd|fe[8-9 a-f])' = Remove non-routed networks
#     fc|fd = fc00::/7 ULA, Unique Local IPv6 Unicast Addresses, RFC 4193
#     fe8|fe9|fea|feb = fe80::/10, Link-Local IPv6 Unicast Addresses, RFC 4291
#     fec|fed|fee|fef = fec0::/10, Site-Local IPv6 Unicast Addresses, RFC 4291
# awk -F "::/64" '{print substr($1,1,19)}' = Shorten to the prefix.
# sort -u = Remove duplicates.
# tail -n 1 = Newer networks are listed at the bottom.
#             Last entry therefore is the current IPv6 prefix.
publicIPv6Net=`route -n show -inet6 | grep $interface \
               | grep ::/64 | grep -vE '^(fc|fd|fe[8-9 a-f])' \
               | awk -F "::/64" '{print substr($1,1,19)}' \
               | sort -u | tail -n 1`

[ "$publicIPv6Net" == "" ] && exit

if [ ! -f /tmp/lastPublicIPv6Net-$interface ] \
|| [ "$publicIPv6Net" != "`cat /tmp/lastPublicIPv6Net-$interface`" ]
then
	lastPublicIPv6Net=`cat /tmp/lastPublicIPv6Net-$interface` 2> /dev/null
	echo $publicIPv6Net > /tmp/lastPublicIPv6Net-$interface
	change "$publicIPv6Net" "$lastPublicIPv6Net"
fi
