1
0

profiles/ds-lite: Connect to Netcologne with PPP DS-Lite

This commit is contained in:
2025-10-27 21:26:28 +01:00
parent 44afbff445
commit f3629c2653
10 changed files with 307 additions and 1 deletions

View File

@@ -0,0 +1,12 @@
{ pkgs, ... }:
pkgs.writeShellApplication {
name = "ds-lite-dhcpcd-hook";
text = builtins.readFile ./ds-lite-dhcpcd-hook.sh;
runtimeInputs = with pkgs; [
iproute2
jq
dig
gawk
];
}

View File

@@ -0,0 +1,102 @@
#!/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"