at 21.11-pre 4.4 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.pppd; 7in 8{ 9 meta = { 10 maintainers = with maintainers; [ danderson ]; 11 }; 12 13 options = { 14 services.pppd = { 15 enable = mkEnableOption "pppd"; 16 17 package = mkOption { 18 default = pkgs.ppp; 19 defaultText = "pkgs.ppp"; 20 type = types.package; 21 description = "pppd package to use."; 22 }; 23 24 peers = mkOption { 25 default = {}; 26 description = "pppd peers."; 27 type = types.attrsOf (types.submodule ( 28 { name, ... }: 29 { 30 options = { 31 name = mkOption { 32 type = types.str; 33 default = name; 34 example = "dialup"; 35 description = "Name of the PPP peer."; 36 }; 37 38 enable = mkOption { 39 type = types.bool; 40 default = true; 41 example = false; 42 description = "Whether to enable this PPP peer."; 43 }; 44 45 autostart = mkOption { 46 type = types.bool; 47 default = true; 48 example = false; 49 description = "Whether the PPP session is automatically started at boot time."; 50 }; 51 52 config = mkOption { 53 type = types.lines; 54 default = ""; 55 description = "pppd configuration for this peer, see the pppd(8) man page."; 56 }; 57 }; 58 })); 59 }; 60 }; 61 }; 62 63 config = let 64 enabledConfigs = filter (f: f.enable) (attrValues cfg.peers); 65 66 mkEtc = peerCfg: { 67 name = "ppp/peers/${peerCfg.name}"; 68 value.text = peerCfg.config; 69 }; 70 71 mkSystemd = peerCfg: { 72 name = "pppd-${peerCfg.name}"; 73 value = { 74 restartTriggers = [ config.environment.etc."ppp/peers/${peerCfg.name}".source ]; 75 before = [ "network.target" ]; 76 wants = [ "network.target" ]; 77 after = [ "network-pre.target" ]; 78 environment = { 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"; 84 }; 85 serviceConfig = { 86 ExecStart = "${getBin cfg.package}/sbin/pppd call ${peerCfg.name} nodetach nolog"; 87 Restart = "always"; 88 RestartSec = 5; 89 90 AmbientCapabilities = "CAP_SYS_TTY_CONFIG CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_ADMIN"; 91 CapabilityBoundingSet = "CAP_SYS_TTY_CONFIG CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_ADMIN"; 92 KeyringMode = "private"; 93 LockPersonality = true; 94 MemoryDenyWriteExecute = true; 95 NoNewPrivileges = true; 96 PrivateMounts = true; 97 PrivateTmp = true; 98 ProtectControlGroups = true; 99 ProtectHome = true; 100 ProtectHostname = true; 101 ProtectKernelModules = true; 102 # pppd can be configured to tweak kernel settings. 103 ProtectKernelTunables = false; 104 ProtectSystem = "strict"; 105 RemoveIPC = true; 106 RestrictAddressFamilies = "AF_PACKET AF_UNIX AF_PPPOX AF_ATMPVC AF_ATMSVC AF_INET AF_INET6 AF_IPX"; 107 RestrictNamespaces = true; 108 RestrictRealtime = true; 109 RestrictSUIDSGID = true; 110 SecureBits = "no-setuid-fixup-locked noroot-locked"; 111 SystemCallFilter = "@system-service"; 112 SystemCallArchitectures = "native"; 113 114 # All pppd instances on a system must share a runtime 115 # directory in order for PPP multilink to work correctly. So 116 # we give all instances the same /run/pppd directory to store 117 # things in. 118 # 119 # For the same reason, we can't set PrivateUsers=true, because 120 # all instances need to run as the same user to access the 121 # multilink database. 122 RuntimeDirectory = "pppd"; 123 RuntimeDirectoryPreserve = true; 124 }; 125 wantedBy = mkIf peerCfg.autostart [ "multi-user.target" ]; 126 }; 127 }; 128 129 etcFiles = listToAttrs (map mkEtc enabledConfigs); 130 systemdConfigs = listToAttrs (map mkSystemd enabledConfigs); 131 132 in mkIf cfg.enable { 133 environment.etc = etcFiles; 134 systemd.services = systemdConfigs; 135 }; 136}