103 lines
3.4 KiB
Bash
103 lines
3.4 KiB
Bash
#!/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 "<ds-lite-dhcpcd-hook> ${WAN_INTERFACE_NAME}: $1"
|
|
}
|
|
|
|
log_tunnel () {
|
|
echo "<ds-lite-dhcpcd-hook> ${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"
|