ndppd module: refactor
This commit is contained in:
parent
f1b91b5726
commit
4ce1c59389
@ -5,43 +5,161 @@ with lib;
|
|||||||
let
|
let
|
||||||
cfg = config.services.ndppd;
|
cfg = config.services.ndppd;
|
||||||
|
|
||||||
configFile = pkgs.runCommand "ndppd.conf" {} ''
|
render = s: f: concatStringsSep "\n" (mapAttrsToList f s);
|
||||||
substitute ${pkgs.ndppd}/etc/ndppd.conf $out \
|
prefer = a: b: if a != null then a else b;
|
||||||
--replace eth0 ${cfg.interface} \
|
|
||||||
--replace 1111:: ${cfg.network}
|
ndppdConf = prefer cfg.configFile (pkgs.writeText "ndppd.conf" ''
|
||||||
'';
|
route-ttl ${toString cfg.routeTTL}
|
||||||
in {
|
${render cfg.proxies (proxyInterfaceName: proxy: ''
|
||||||
|
proxy ${prefer proxy.interface proxyInterfaceName} {
|
||||||
|
router ${boolToString proxy.router}
|
||||||
|
timeout ${toString proxy.timeout}
|
||||||
|
ttl ${toString proxy.ttl}
|
||||||
|
${render proxy.rules (ruleNetworkName: rule: ''
|
||||||
|
rule ${prefer rule.network ruleNetworkName} {
|
||||||
|
${rule.method}${if rule.method == "iface" then " ${rule.interface}" else ""}
|
||||||
|
}'')}
|
||||||
|
}'')}
|
||||||
|
'');
|
||||||
|
|
||||||
|
proxy = types.submodule {
|
||||||
options = {
|
options = {
|
||||||
services.ndppd = {
|
interface = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
description = ''
|
||||||
|
Listen for any Neighbor Solicitation messages on this interface,
|
||||||
|
and respond to them according to a set of rules.
|
||||||
|
Defaults to the name of the attrset.
|
||||||
|
'';
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
router = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Turns on or off the router flag for Neighbor Advertisement Messages.
|
||||||
|
'';
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
timeout = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
description = ''
|
||||||
|
Controls how long to wait for a Neighbor Advertisment Message before
|
||||||
|
invalidating the entry, in milliseconds.
|
||||||
|
'';
|
||||||
|
default = 500;
|
||||||
|
};
|
||||||
|
ttl = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
description = ''
|
||||||
|
Controls how long a valid or invalid entry remains in the cache, in
|
||||||
|
milliseconds.
|
||||||
|
'';
|
||||||
|
default = 30000;
|
||||||
|
};
|
||||||
|
rules = mkOption {
|
||||||
|
type = types.attrsOf rule;
|
||||||
|
description = ''
|
||||||
|
This is a rule that the target address is to match against. If no netmask
|
||||||
|
is provided, /128 is assumed. You may have several rule sections, and the
|
||||||
|
addresses may or may not overlap.
|
||||||
|
'';
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
rule = types.submodule {
|
||||||
|
options = {
|
||||||
|
network = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
description = ''
|
||||||
|
This is the target address is to match against. If no netmask
|
||||||
|
is provided, /128 is assumed. The addresses of serveral rules
|
||||||
|
may or may not overlap.
|
||||||
|
Defaults to the name of the attrset.
|
||||||
|
'';
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
method = mkOption {
|
||||||
|
type = types.enum [ "static" "iface" "auto" ];
|
||||||
|
description = ''
|
||||||
|
static: Immediately answer any Neighbor Solicitation Messages
|
||||||
|
(if they match the IP rule).
|
||||||
|
iface: Forward the Neighbor Solicitation Message through the specified
|
||||||
|
interface and only respond if a matching Neighbor Advertisement
|
||||||
|
Message is received.
|
||||||
|
auto: Same as iface, but instead of manually specifying the outgoing
|
||||||
|
interface, check for a matching route in /proc/net/ipv6_route.
|
||||||
|
'';
|
||||||
|
default = "auto";
|
||||||
|
};
|
||||||
|
interface = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
description = "Interface to use when method is iface.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.services.ndppd = {
|
||||||
enable = mkEnableOption "daemon that proxies NDP (Neighbor Discovery Protocol) messages between interfaces";
|
enable = mkEnableOption "daemon that proxies NDP (Neighbor Discovery Protocol) messages between interfaces";
|
||||||
interface = mkOption {
|
interface = mkOption {
|
||||||
type = types.string;
|
type = types.nullOr types.str;
|
||||||
default = "eth0";
|
description = ''
|
||||||
example = "ens3";
|
Interface which is on link-level with router.
|
||||||
description = "Interface which is on link-level with router.";
|
(Legacy option, use services.ndppd.proxies.<interface>.rules.<network> instead)
|
||||||
|
'';
|
||||||
|
default = null;
|
||||||
|
example = "eth0";
|
||||||
};
|
};
|
||||||
network = mkOption {
|
network = mkOption {
|
||||||
type = types.string;
|
type = types.nullOr types.str;
|
||||||
default = "1111::";
|
description = ''
|
||||||
example = "2001:DB8::/32";
|
Network that we proxy.
|
||||||
description = "Network that we proxy.";
|
(Legacy option, use services.ndppd.proxies.<interface>.rules.<network> instead)
|
||||||
|
'';
|
||||||
|
default = null;
|
||||||
|
example = "1111::/64";
|
||||||
};
|
};
|
||||||
configFile = mkOption {
|
configFile = mkOption {
|
||||||
type = types.nullOr types.path;
|
type = types.nullOr types.path;
|
||||||
default = null;
|
|
||||||
description = "Path to configuration file.";
|
description = "Path to configuration file.";
|
||||||
|
default = null;
|
||||||
};
|
};
|
||||||
|
routeTTL = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
description = ''
|
||||||
|
This tells 'ndppd' how often to reload the route file /proc/net/ipv6_route,
|
||||||
|
in milliseconds.
|
||||||
|
'';
|
||||||
|
default = 30000;
|
||||||
|
};
|
||||||
|
proxies = mkOption {
|
||||||
|
type = types.attrsOf proxy;
|
||||||
|
description = ''
|
||||||
|
This sets up a listener, that will listen for any Neighbor Solicitation
|
||||||
|
messages, and respond to them according to a set of rules.
|
||||||
|
'';
|
||||||
|
default = {};
|
||||||
|
example = { "eth0".rules."1111::/64" = {}; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
systemd.packages = [ pkgs.ndppd ];
|
warnings = mkIf (cfg.interface != null && cfg.network != null) [ ''
|
||||||
environment.etc."ndppd.conf".source = if (cfg.configFile != null) then cfg.configFile else configFile;
|
The options services.ndppd.interface and services.ndppd.network will probably be removed soon,
|
||||||
systemd.services.ndppd = {
|
please use services.ndppd.proxies.<interface>.rules.<network> instead.
|
||||||
serviceConfig.RuntimeDirectory = [ "ndppd" ];
|
'' ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
};
|
services.ndppd.proxies = mkIf (cfg.interface != null && cfg.network != null) {
|
||||||
|
"${cfg.interface}".rules."${cfg.network}" = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
meta.maintainers = with maintainers; [ gnidorah ];
|
systemd.services.ndppd = {
|
||||||
|
after = [ "network-pre.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig.ExecStart = "${pkgs.ndppd}/bin/ndppd -c ${ndppdConf}";
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user