nixpkgs/nixos/modules/services/networking/pppd.nix
Martin Weinelt ee26807e35
nixos/pppd: allow AF_NETLINK
The pppd daemon starting with version 2.4.9 uses rtnetlink to configure
the ipv6 peer address on the ppp interface. It therefore requires
allowing AF_NETLINK sockets.
2021-07-21 16:38:51 +02:00

154 lines
4.5 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.pppd;
in
{
meta = {
maintainers = with maintainers; [ danderson ];
};
options = {
services.pppd = {
enable = mkEnableOption "pppd";
package = mkOption {
default = pkgs.ppp;
defaultText = "pkgs.ppp";
type = types.package;
description = "pppd package to use.";
};
peers = mkOption {
default = {};
description = "pppd peers.";
type = types.attrsOf (types.submodule (
{ name, ... }:
{
options = {
name = mkOption {
type = types.str;
default = name;
example = "dialup";
description = "Name of the PPP peer.";
};
enable = mkOption {
type = types.bool;
default = true;
example = false;
description = "Whether to enable this PPP peer.";
};
autostart = mkOption {
type = types.bool;
default = true;
example = false;
description = "Whether the PPP session is automatically started at boot time.";
};
config = mkOption {
type = types.lines;
default = "";
description = "pppd configuration for this peer, see the pppd(8) man page.";
};
};
}));
};
};
};
config = let
enabledConfigs = filter (f: f.enable) (attrValues cfg.peers);
mkEtc = peerCfg: {
name = "ppp/peers/${peerCfg.name}";
value.text = peerCfg.config;
};
mkSystemd = peerCfg: {
name = "pppd-${peerCfg.name}";
value = {
restartTriggers = [ config.environment.etc."ppp/peers/${peerCfg.name}".source ];
before = [ "network.target" ];
wants = [ "network.target" ];
after = [ "network-pre.target" ];
environment = {
# pppd likes to write directly into /var/run. This is rude
# on a modern system, so we use libredirect to transparently
# move those files into /run/pppd.
LD_PRELOAD = "${pkgs.libredirect}/lib/libredirect.so";
NIX_REDIRECTS = "/var/run=/run/pppd";
};
serviceConfig = let
capabilities = [
"CAP_BPF"
"CAP_SYS_TTY_CONFIG"
"CAP_NET_ADMIN"
"CAP_NET_RAW"
];
in
{
ExecStart = "${getBin cfg.package}/sbin/pppd call ${peerCfg.name} nodetach nolog";
Restart = "always";
RestartSec = 5;
AmbientCapabilities = capabilities;
CapabilityBoundingSet = capabilities;
KeyringMode = "private";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateMounts = true;
PrivateTmp = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelModules = true;
# pppd can be configured to tweak kernel settings.
ProtectKernelTunables = false;
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_ATMPVC"
"AF_ATMSVC"
"AF_INET"
"AF_INET6"
"AF_IPX"
"AF_NETLINK"
"AF_PACKET"
"AF_PPPOX"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SecureBits = "no-setuid-fixup-locked noroot-locked";
SystemCallFilter = "@system-service";
SystemCallArchitectures = "native";
# All pppd instances on a system must share a runtime
# directory in order for PPP multilink to work correctly. So
# we give all instances the same /run/pppd directory to store
# things in.
#
# For the same reason, we can't set PrivateUsers=true, because
# all instances need to run as the same user to access the
# multilink database.
RuntimeDirectory = "pppd";
RuntimeDirectoryPreserve = true;
};
wantedBy = mkIf peerCfg.autostart [ "multi-user.target" ];
};
};
etcFiles = listToAttrs (map mkEtc enabledConfigs);
systemdConfigs = listToAttrs (map mkSystemd enabledConfigs);
in mkIf cfg.enable {
environment.etc = etcFiles;
systemd.services = systemdConfigs;
};
}