ndppd module: refactor

This commit is contained in:
elseym 2019-02-02 15:37:48 +01:00
parent f1b91b5726
commit 4ce1c59389
No known key found for this signature in database
GPG Key ID: 8696D1F9E5C020D2

View File

@ -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}";
};
};
} }