1 { config, lib, pkgs, ... }:
6 cfg = config.services.pppd;
10 maintainers = with maintainers; [ danderson ];
15 enable = mkEnableOption (lib.mdDoc "pppd");
19 defaultText = literalExpression "pkgs.ppp";
21 description = lib.mdDoc "pppd package to use.";
26 description = lib.mdDoc "pppd peers.";
27 type = types.attrsOf (types.submodule (
35 description = lib.mdDoc "Name of the PPP peer.";
42 description = lib.mdDoc "Whether to enable this PPP peer.";
45 autostart = mkOption {
49 description = lib.mdDoc "Whether the PPP session is automatically started at boot time.";
55 description = lib.mdDoc "pppd configuration for this peer, see the pppd(8) man page.";
64 enabledConfigs = filter (f: f.enable) (attrValues cfg.peers);
67 name = "ppp/peers/${peerCfg.name}";
68 value.text = peerCfg.config;
71 mkSystemd = peerCfg: {
72 name = "pppd-${peerCfg.name}";
74 restartTriggers = [ config.environment.etc."ppp/peers/${peerCfg.name}".source ];
75 before = [ "network.target" ];
76 wants = [ "network.target" ];
77 after = [ "network-pre.target" ];
79 # pppd likes to write directly into /var/run. This is rude
80 # on a modern system, so we use libredirect to transparently
81 # move those files into /run/pppd.
82 LD_PRELOAD = "${pkgs.libredirect}/lib/libredirect.so";
83 NIX_REDIRECTS = "/var/run=/run/pppd";
94 ExecStart = "${getBin cfg.package}/sbin/pppd call ${peerCfg.name} nodetach nolog";
98 AmbientCapabilities = capabilities;
99 CapabilityBoundingSet = capabilities;
100 KeyringMode = "private";
101 LockPersonality = true;
102 MemoryDenyWriteExecute = true;
103 NoNewPrivileges = true;
104 PrivateMounts = true;
106 ProtectControlGroups = true;
108 ProtectHostname = true;
109 ProtectKernelModules = true;
110 # pppd can be configured to tweak kernel settings.
111 ProtectKernelTunables = false;
112 ProtectSystem = "strict";
114 RestrictAddressFamilies = [
125 RestrictNamespaces = true;
126 RestrictRealtime = true;
127 RestrictSUIDSGID = true;
128 SecureBits = "no-setuid-fixup-locked noroot-locked";
129 SystemCallFilter = "@system-service";
130 SystemCallArchitectures = "native";
132 # All pppd instances on a system must share a runtime
133 # directory in order for PPP multilink to work correctly. So
134 # we give all instances the same /run/pppd directory to store
137 # For the same reason, we can't set PrivateUsers=true, because
138 # all instances need to run as the same user to access the
139 # multilink database.
140 RuntimeDirectory = "pppd";
141 RuntimeDirectoryPreserve = true;
143 wantedBy = mkIf peerCfg.autostart [ "multi-user.target" ];
147 etcFiles = listToAttrs (map mkEtc enabledConfigs);
148 systemdConfigs = listToAttrs (map mkSystemd enabledConfigs);
151 environment.etc = etcFiles;
152 systemd.services = systemdConfigs;