fix-ip6-default-route.sh: Added script to monitor IPv6 default route master
authorMegaBrutal <code+git@megabrutal.com>
Fri, 5 Jan 2018 08:30:00 +0000 (09:30 +0100)
committerMegaBrutal <code+git@megabrutal.com>
Fri, 5 Jan 2018 08:30:00 +0000 (09:30 +0100)
Added a Debian/Ubuntu specific script to check the IPv6 default route
of the host, whether it is absent or configured from RA while it is
supposed to be static.

This is necessary because LXC containers are often affected by a
race condition, when the interface has a static config, but it gets
a default route through Router Advertisement before RAs get disabled.

For reference:
https://www.mail-archive.com/lxc-users@lists.linuxcontainers.org/msg07776.html
https://github.com/lxc/lxd/issues/3582

Although a bit messy, this script is intended to be fool-proof, so
it does not do any harm if it is run on a host where it has no use
to run. So you can deploy it to all LXC containers in your uniform
environment where RA, DHCPv6 and statically configured containers
may co-exist. It is advised to schedule this script (e.g. with cron)
to have it periodically check the IPv6 default route. Unless the -v
(verbose) option is supplied, the script should only have output
when it does some action, otherwise it's silent.

The script checks whether there are only static IPv6 interface
configurations listed in /etc/network/interfaces. If any interface
is automatically configured on purpose, the script stops (as it is
assumed the host is supposed to get its default route through
automatic configuration). If only static inet6 interface configs
exist and a default route is clearly defined, it checks the IPv6
default route. If there is no default route, or it is received
from RA, the script resets the interface and reconfigures it with
ifup.

        new file:   host/fix-ip6-default-route.sh

host/fix-ip6-default-route.sh [new file with mode: 0755]

diff --git a/host/fix-ip6-default-route.sh b/host/fix-ip6-default-route.sh
new file mode 100755 (executable)
index 0000000..7eb91f2
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/sh
+export PATH=${PATH}:/sbin
+NETCFG=/etc/network/interfaces
+
+[ "$1" = "-v" ] && DEBUG="printf" || DEBUG="true"
+
+lastiface=""
+lastgateway=""
+
+while read -r line
+do
+       if echo "${line}" | grep -q "[ \t]*#"
+       then
+               false
+       elif echo "${line}" | grep -q "^iface [^ ]* inet6 [^ ]*$"
+       then
+               echo "${line}" | ( IFS=' ' read -r _ iface _ method
+                       "${DEBUG}" "Found %s with method %s.\n" "${iface}" "${method}"
+                       if [ "${method}" != "static" ]
+                       then
+                               "${DEBUG}" "Interface %s does not use static configuration. Ambiguous config, exiting.\n" "${iface}"
+                               exit 2
+                       fi
+               ) || exit $?
+               lastiface="${line}"
+       elif [ -n "${lastiface}" ]
+       then
+               if gateway=$(echo "${line}" | grep -o "gateway *[0-9a-fA-F:]*:[0-9a-fA-F:]*")
+               then
+                       if [ -z "${lastgateway}" ]
+                       then
+                               lastgateway="${gateway}"
+                               "${DEBUG}" "Found %s for %s.\n" "${lastgateway}" "${lastiface}"
+                       else
+                               "${DEBUG}" "A gateway was already defined for another interface. Ambiguous situation, exiting.\n"
+                               exit 3
+                       fi
+               fi
+       fi
+done < "${NETCFG}"
+
+if [ -z "${lastiface}" ]
+then
+       "${DEBUG}" "No inet6 interface config found.\n"
+       exit 1
+else
+       iface=$(echo "${lastiface}" | grep -oP "(?<=iface )[^ ]*(?= inet6)")
+       "${DEBUG}" "Checking if %s needs to be reconfigured...\n" "${iface}"
+fi
+
+defroute=$(ip -6 route | grep "^default ")
+if [ -z "${defroute}" ] || echo "${defroute}" | grep -q " proto ra "
+then
+       # If we get here, we will provide output of our actions. It is not affected by verbose mode.
+       printf "No default route, or it is RA-configured. Reconfiguring %s...\n" "${iface}"
+       ifdown -v "${iface}"
+       ip link set "${iface}" down
+       ifup -v "${iface}"
+else
+       "${DEBUG}" "Found healthy default route: %s.\nNo action is necessary.\n" "${defroute}"
+fi