From f3629c2653f311398bfa5fad876b2744ffc66b40 Mon Sep 17 00:00:00 2001 From: clerie Date: Mon, 27 Oct 2025 21:26:28 +0100 Subject: [PATCH 1/2] profiles/ds-lite: Connect to Netcologne with PPP DS-Lite --- hosts/carbon/configuration.nix | 3 +- hosts/carbon/ds-lite-ncfttb.nix | 18 +++ hosts/carbon/{ppp.nix => ppp-ncfttb.nix} | 0 pkgs/ds-lite-dhcpcd-hook/default.nix | 12 ++ .../ds-lite-dhcpcd-hook.sh | 102 ++++++++++++ pkgs/overlay.nix | 1 + pkgs/overrides/ds-lite-dhcpcd.nix | 20 +++ pkgs/overrides/overlay.nix | 1 + profiles/default.nix | 1 + profiles/ds-lite/default.nix | 150 ++++++++++++++++++ 10 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 hosts/carbon/ds-lite-ncfttb.nix rename hosts/carbon/{ppp.nix => ppp-ncfttb.nix} (100%) create mode 100644 pkgs/ds-lite-dhcpcd-hook/default.nix create mode 100644 pkgs/ds-lite-dhcpcd-hook/ds-lite-dhcpcd-hook.sh create mode 100644 pkgs/overrides/ds-lite-dhcpcd.nix create mode 100644 profiles/ds-lite/default.nix diff --git a/hosts/carbon/configuration.nix b/hosts/carbon/configuration.nix index b80e961..8b50085 100644 --- a/hosts/carbon/configuration.nix +++ b/hosts/carbon/configuration.nix @@ -6,6 +6,7 @@ ./hardware-configuration.nix ./dns.nix + ./ds-lite-ncfttb.nix ./mdns.nix ./net-dsl.nix ./net-gastnetz.nix @@ -16,7 +17,7 @@ ./net-printer.nix ./net-voip.nix ./ntp.nix - ./ppp.nix + ./ppp-ncfttb.nix ./scan-to-gpg.nix ./wg-clerie.nix ]; diff --git a/hosts/carbon/ds-lite-ncfttb.nix b/hosts/carbon/ds-lite-ncfttb.nix new file mode 100644 index 0000000..ecd06dc --- /dev/null +++ b/hosts/carbon/ds-lite-ncfttb.nix @@ -0,0 +1,18 @@ +{ ... }: + +{ + + profiles.clerie.ds-lite = { + enable = true; + wanInterfaceName = "ppp-ncfttb"; + tunnelInterfaceName = "ds-lite-ncfttb"; + lanInterfaces = [ + { + name = "net-heimnetz"; + sla_id = 201; + prefix_len = 64; + } + ]; + }; + +} diff --git a/hosts/carbon/ppp.nix b/hosts/carbon/ppp-ncfttb.nix similarity index 100% rename from hosts/carbon/ppp.nix rename to hosts/carbon/ppp-ncfttb.nix diff --git a/pkgs/ds-lite-dhcpcd-hook/default.nix b/pkgs/ds-lite-dhcpcd-hook/default.nix new file mode 100644 index 0000000..b5dc98e --- /dev/null +++ b/pkgs/ds-lite-dhcpcd-hook/default.nix @@ -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 + ]; +} diff --git a/pkgs/ds-lite-dhcpcd-hook/ds-lite-dhcpcd-hook.sh b/pkgs/ds-lite-dhcpcd-hook/ds-lite-dhcpcd-hook.sh new file mode 100644 index 0000000..32f025f --- /dev/null +++ b/pkgs/ds-lite-dhcpcd-hook/ds-lite-dhcpcd-hook.sh @@ -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 " ${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" diff --git a/pkgs/overlay.nix b/pkgs/overlay.nix index a606320..bea8a32 100644 --- a/pkgs/overlay.nix +++ b/pkgs/overlay.nix @@ -14,6 +14,7 @@ final: prev: { chromium-incognito = final.callPackage ./chromium-incognito {}; convert-flac-dir-to-mp3 = final.callPackage ./convert-flac-dir-to-mp3 {}; curl-timings = final.callPackage ./curl-timings {}; + ds-lite-dhcpcd-hook = final.callPackage ./ds-lite-dhcpcd-hook {}; factorio-launcher = final.callPackage ./factorio-launcher {}; feeds-dir = final.callPackage ./feeds-dir {}; generate-blocked-prefixes = final.callPackage ./generate-blocked-prefixes {}; diff --git a/pkgs/overrides/ds-lite-dhcpcd.nix b/pkgs/overrides/ds-lite-dhcpcd.nix new file mode 100644 index 0000000..6c04ec3 --- /dev/null +++ b/pkgs/overrides/ds-lite-dhcpcd.nix @@ -0,0 +1,20 @@ +final: prev: +prev.dhcpcd.overrideAttrs (finalAttrs: prevAttrs: { + + configureFlags = [ + "--sysconfdir=/etc/ds-lite-dhcpcd" + "--localstatedir=/var" + "--disable-fork" + "--disable-privsep" + "--dbdir=/var/lib/ds-lite-dhcpcd" + "--rundir=/var/run/ds-lite-dhcpcd" + "--with-default-hostname=ds-lite" + "--disable-ipv4" + "--disable-arp" + "--disable-arpping" + "--disable-ipv4ll" + "--disable-ntp" + ]; + +}) + diff --git a/pkgs/overrides/overlay.nix b/pkgs/overrides/overlay.nix index 914a9e3..34d4668 100644 --- a/pkgs/overrides/overlay.nix +++ b/pkgs/overrides/overlay.nix @@ -1,4 +1,5 @@ final: prev: { dino = import ./dino.nix final prev; + ds-lite-dhcpcd = import ./ds-lite-dhcpcd.nix final prev; xmppc = import ./xmppc.nix final prev; } diff --git a/profiles/default.nix b/profiles/default.nix index 3e12719..be4303c 100644 --- a/profiles/default.nix +++ b/profiles/default.nix @@ -11,6 +11,7 @@ ./cybercluster-vm ./desktop ./dn42-router + ./ds-lite ./fem-net ./firefox ./gpg-ssh diff --git a/profiles/ds-lite/default.nix b/profiles/ds-lite/default.nix new file mode 100644 index 0000000..052450f --- /dev/null +++ b/profiles/ds-lite/default.nix @@ -0,0 +1,150 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.profiles.clerie.ds-lite; + + + dsLiteDhcpcdConfig = '' + allowinterfaces ${cfg.wanInterfaceName} ${concatMapStringsSep " " (interface: interface.name) cfg.lanInterfaces} + + option dhcp6_name_servers + option dhcp6_aftr_name + + waitip 6 + + ipv6only + ipv6ra_noautoconf + noipv6rs + + interface ${cfg.wanInterfaceName} + ipv6ra_autoconf + ipv6rs + ia_pd 1/::/48 ${concatMapStringsSep " " (interface: "${interface.name}/${toString interface.sla_id}/${toString interface.prefix_len}") cfg.lanInterfaces} + + ${concatMapStrings (interface: '' + interface ${interface.name} + nolink + '') cfg.lanInterfaces} + ''; + + dsLiteDhcpcdConfigFile = pkgs.writeTextFile { + name = "dhcpcd.conf"; + text = dsLiteDhcpcdConfig; + }; + + dsLiteDhcpcdHookWrapperFile = pkgs.writeShellScript "ds-lite-dhcpcd-hook-wrapper" '' + DS_LITE_WAN_INTERFACE_NAME=${lib.escapeShellArg cfg.wanInterfaceName}; + export DS_LITE_WAN_INTERFACE_NAME + DS_LITE_TUNNEL_INTERFACE_NAME=${lib.escapeShellArg cfg.tunnelInterfaceName}; + export DS_LITE_TUNNEL_INTERFACE_NAME + + exec ${lib.getExe pkgs.ds-lite-dhcpcd-hook} + ''; + +in { + + options.profiles.clerie.ds-lite = { + enable = mkEnableOption "DS-Lite setup"; + wanInterfaceName = mkOption { + type = types.str; + description = "Interface with IPv6 connectivity to provider"; + }; + tunnelInterfaceName = mkOption { + type = types.str; + description = "Interface with IPv4 connectivity to provider"; + }; + lanInterfaces = mkOption { + type = with types; listOf (submodule ({ ... }: { + options = { + name = mkOption { + type = types.str; + }; + sla_id = mkOption { + type = types.ints.unsigned; + }; + prefix_len = mkOption { + type = types.ints.between 48 128; + }; + }; + })); + default = []; + description = "Interfaces to provisn with an IPv6 prefix"; + }; + }; + + config = mkIf cfg.enable { + systemd.services.ds-lite-dhcpcd = { + description = "DS-Lite dhcpcd"; + + wantedBy = [ "multi-user.target" ]; + + environment = { + }; + + serviceConfig = { + Type = "simple"; + User = "ds-lite"; + Group = "ds-lite"; + StateDirectory = "ds-lite-dhcpcd"; + RuntimeDirectory = "ds-lite-dhcpcd"; + + ExecStart = "${pkgs.ds-lite-dhcpcd}/bin/dhcpcd --ipv6only --nobackground --config ${dsLiteDhcpcdConfigFile} --script ${dsLiteDhcpcdHookWrapperFile}"; + + Restart = "always"; + AmbientCapabilities = [ + "CAP_NET_ADMIN" + "CAP_NET_RAW" + "CAP_NET_BIND_SERVICE" + ]; + ReadWritePaths = [ + "/proc/sys/net/ipv6" + ]; + DeviceAllow = ""; + LockPersonality = true; + MemoryDenyWriteExecute = true; + PrivateDevices = true; + PrivateMounts = true; + PrivateTmp = true; + PrivateUsers = false; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = "tmpfs"; # allow exceptions to be added to ReadOnlyPaths, etc. + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_UNIX" + "AF_INET" + "AF_INET6" + "AF_NETLINK" + "AF_PACKET" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallFilter = [ + "@system-service" + "~@keyring" + "~@memlock" + "~@mount" + ]; + SystemCallArchitectures = "native"; + UMask = "0027"; + }; + }; + + users.users.ds-lite = { + isSystemUser = true; + group = "ds-lite"; + }; + users.groups.ds-lite = { }; + }; + +} From 9cd78ef9c3f061d2f26a9327553440bd00b8f233 Mon Sep 17 00:00:00 2001 From: Flake Update Bot Date: Tue, 28 Oct 2025 03:03:19 +0100 Subject: [PATCH 2/2] Update nixpkgs 2025-10-28-02-03 --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 73832b0..a7c06c7 100644 --- a/flake.lock +++ b/flake.lock @@ -666,11 +666,11 @@ }, "nixpkgs_5": { "locked": { - "lastModified": 1753549186, - "narHash": "sha256-Znl7rzuxKg/Mdm6AhimcKynM7V3YeNDIcLjBuoBcmNs=", + "lastModified": 1761373498, + "narHash": "sha256-Q/uhWNvd7V7k1H1ZPMy/vkx3F8C13ZcdrKjO7Jv7v0c=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "17f6bd177404d6d43017595c5264756764444ab8", + "rev": "6a08e6bb4e46ff7fcbb53d409b253f6bad8a28ce", "type": "github" }, "original": {