{ 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 = { }; }; }