#!/usr/bin/env bash set -euo pipefail # Setting up required environment variables # shellcheck disable=SC2154 WAN_INTERFACE_NAME="${DS_LITE_WAN_INTERFACE_NAME}" # shellcheck disable=SC2154 TUNNEL_INTERFACE_NAME="${DS_LITE_TUNNEL_INTERFACE_NAME}" log_dhcp () { echo " ${WAN_INTERFACE_NAME}: $1" } log_tunnel () { echo " ${WAN_INTERFACE_NAME} (${TUNNEL_INTERFACE_NAME}): $1" } # Check if the event calling this hook is for the wan interface # exit immediately if not # shellcheck disable=SC2154 if [[ "$interface" != "$WAN_INTERFACE_NAME" ]]; then exit fi # Make sure the event calling this hook carries the environment variable # in question. The environment variable is not provided with every call # and we just want to exit if it is not provided # shellcheck disable=SC2154 if [[ ! -v new_dhcp6_aftr_name ]]; then # Variable is not set exit fi # shellcheck disable=SC2154 if [[ -z "${new_dhcp6_aftr_name}" ]]; then # Variable is empty, can't do anything exit fi # shellcheck disable=SC2154 AFTR_NAME="$new_dhcp6_aftr_name" log_dhcp "Received new AFTR_NAME ${AFTR_NAME}" # Make sure we have a nameserver to resolve aftr name against # shellcheck disable=SC2154 if [[ ! -v new_dhcp6_name_servers ]]; then # Variable is not set exit fi # shellcheck disable=SC2154 if [[ -z "${new_dhcp6_name_servers}" ]]; then # Variable is empty, can't do anything exit fi # shellcheck disable=SC2154 NAME_SERVERS="$new_dhcp6_name_servers" log_dhcp "Received new NAME_SERVERS ${NAME_SERVERS}" # Select first nameserver NAME_SERVER="$(echo "${NAME_SERVERS}" | awk '{print $1;}')" log_dhcp "Selected NAME_SERVER ${NAME_SERVER}" # Figure out a usable IPv6 address on the wan interface, to origin our DNS requests and tunnel WAN_INTERFACE_ADDRESS="$(ip --json address show "${WAN_INTERFACE_NAME}" | jq -r '.[0].addr_info[] | select(.family == "inet6" and .scope == "global" and .mngtmpaddr == true) | .local')" log_dhcp "Using WAN_INTERFACE_ADDRESS ${WAN_INTERFACE_ADDRESS}" AFTR_ADDRESS="$(dig "@${NAME_SERVER}" -b "${WAN_INTERFACE_ADDRESS}" AAAA "${AFTR_NAME}" +short | head -1)" log_dhcp "Resolved AFTR_NAME ${AFTR_NAME} to ${AFTR_ADDRESS}" # Check if there is already a tunnel interface if TUNNEL_INTERFACE_CONFIG="$(ip --json link show "${TUNNEL_INTERFACE_NAME}")"; then TUNNEL_INTERFACE_OPERSTATE="$(echo "${TUNNEL_INTERFACE_CONFIG}" | jq -r '.[0].operstate')" TUNNEL_INTERFACE_ORIGIN_ADDRESS="$(echo "${TUNNEL_INTERFACE_CONFIG}" | jq -r '.[0].address')" TUNNEL_INTERFACE_REMOTE_ADDRESS="$(echo "${TUNNEL_INTERFACE_CONFIG}" | jq -r '.[0].broadcast')" # Reconfigure tunnel interface, if not already in state we want if [[ "${TUNNEL_INTERFACE_ORIGIN_ADDRESS}" != "${WAN_INTERFACE_ADDRESS}" || "${TUNNEL_INTERFACE_REMOTE_ADDRESS}" != "${AFTR_ADDRESS}" || "${TUNNEL_INTERFACE_OPERSTATE}" != "UNKNOWN" ]]; then log_tunnel "Bad configuration, fixing tunnel parameter" ip tunnel change "${TUNNEL_INTERFACE_NAME}" mode ipip6 local "${WAN_INTERFACE_ADDRESS}" remote "${AFTR_ADDRESS}" ip link set "$TUNNEL_INTERFACE_NAME" up else log_tunnel "Tunnel already configured" fi else log_tunnel "Setting up DS-Lite tunnel" ip tunnel add "${TUNNEL_INTERFACE_NAME}" mode ipip6 local "${WAN_INTERFACE_ADDRESS}" remote "${AFTR_ADDRESS}" ip link set "$TUNNEL_INTERFACE_NAME" up fi log_tunnel "Setting default route" ip route replace default dev "${TUNNEL_INTERFACE_NAME}" log_tunnel "Tunnel setup finished"