commit
70a6628848
@ -164,6 +164,9 @@ with lib;
|
|||||||
else { addr = value inetAddr; port = value inetPort; }
|
else { addr = value inetAddr; port = value inetPort; }
|
||||||
))
|
))
|
||||||
|
|
||||||
|
# dhcpd
|
||||||
|
(mkRenamedOptionModule [ "services" "dhcpd" ] [ "services" "dhcpd4" ])
|
||||||
|
|
||||||
# Options that are obsolete and have no replacement.
|
# Options that are obsolete and have no replacement.
|
||||||
(mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ] "")
|
(mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ] "")
|
||||||
(mkRemovedOptionModule [ "programs" "bash" "enable" ] "")
|
(mkRemovedOptionModule [ "programs" "bash" "enable" ] "")
|
||||||
|
@ -4,11 +4,10 @@ with lib;
|
|||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.services.dhcpd;
|
cfg4 = config.services.dhcpd4;
|
||||||
|
cfg6 = config.services.dhcpd6;
|
||||||
|
|
||||||
stateDir = "/var/lib/dhcp"; # Don't use /var/state/dhcp; not FHS-compliant.
|
writeConfig = cfg: pkgs.writeText "dhcpd.conf"
|
||||||
|
|
||||||
configFile = if cfg.configFile != null then cfg.configFile else pkgs.writeText "dhcpd.conf"
|
|
||||||
''
|
''
|
||||||
default-lease-time 600;
|
default-lease-time 600;
|
||||||
max-lease-time 7200;
|
max-lease-time 7200;
|
||||||
@ -29,21 +28,85 @@ let
|
|||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
in
|
dhcpdService = postfix: cfg: optionalAttrs cfg.enable {
|
||||||
|
"dhcpd${postfix}" = {
|
||||||
|
description = "DHCPv${postfix} server";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "network.target" ];
|
||||||
|
|
||||||
{
|
preStart = ''
|
||||||
|
mkdir -m 755 -p ${cfg.stateDir}
|
||||||
|
touch ${cfg.stateDir}/dhcpd.leases
|
||||||
|
'';
|
||||||
|
|
||||||
###### interface
|
serviceConfig =
|
||||||
|
let
|
||||||
|
configFile = if cfg.configFile != null then cfg.configFile else writeConfig cfg;
|
||||||
|
args = [ "@${pkgs.dhcp}/sbin/dhcpd" "dhcpd${postfix}" "-${postfix}"
|
||||||
|
"-pf" "/run/dhcpd${postfix}/dhcpd.pid"
|
||||||
|
"-cf" "${configFile}"
|
||||||
|
"-lf" "${cfg.stateDir}/dhcpd.leases"
|
||||||
|
"-user" "dhcpd" "-group" "nogroup"
|
||||||
|
] ++ cfg.extraFlags
|
||||||
|
++ cfg.interfaces;
|
||||||
|
|
||||||
options = {
|
in {
|
||||||
|
ExecStart = concatMapStringsSep " " escapeShellArg args;
|
||||||
|
Type = "forking";
|
||||||
|
Restart = "always";
|
||||||
|
RuntimeDirectory = [ "dhcpd${postfix}" ];
|
||||||
|
PIDFile = "/run/dhcpd${postfix}/dhcpd.pid";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
services.dhcpd = {
|
machineOpts = {...}: {
|
||||||
|
config = {
|
||||||
|
|
||||||
|
hostName = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "foo";
|
||||||
|
description = ''
|
||||||
|
Hostname which is assigned statically to the machine.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ethernetAddress = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "00:16:76:9a:32:1d";
|
||||||
|
description = ''
|
||||||
|
MAC address of the machine.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ipAddress = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "192.168.1.10";
|
||||||
|
description = ''
|
||||||
|
IP address of the machine.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
dhcpConfig = postfix: {
|
||||||
|
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = "
|
description = ''
|
||||||
Whether to enable the DHCP server.
|
Whether to enable the DHCPv${postfix} server.
|
||||||
";
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
stateDir = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
# We use /var/lib/dhcp for DHCPv4 to save backwards compatibility.
|
||||||
|
default = "/var/lib/dhcp${if postfix == "4" then "" else postfix}";
|
||||||
|
description = ''
|
||||||
|
State directory for the DHCP server.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
extraConfig = mkOption {
|
extraConfig = mkOption {
|
||||||
@ -59,38 +122,41 @@ in
|
|||||||
range 192.168.1.100 192.168.1.200;
|
range 192.168.1.100 192.168.1.200;
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
description = "
|
description = ''
|
||||||
Extra text to be appended to the DHCP server configuration
|
Extra text to be appended to the DHCP server configuration
|
||||||
file. Currently, you almost certainly need to specify
|
file. Currently, you almost certainly need to specify something
|
||||||
something here, such as the options specifying the subnet
|
there, such as the options specifying the subnet mask, DNS servers,
|
||||||
mask, DNS servers, etc.
|
etc.
|
||||||
";
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
extraFlags = mkOption {
|
extraFlags = mkOption {
|
||||||
default = "";
|
type = types.listOf types.str;
|
||||||
example = "-6";
|
default = [];
|
||||||
description = "
|
description = ''
|
||||||
Additional command line flags to be passed to the dhcpd daemon.
|
Additional command line flags to be passed to the dhcpd daemon.
|
||||||
";
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
configFile = mkOption {
|
configFile = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
default = null;
|
default = null;
|
||||||
description = "
|
description = ''
|
||||||
The path of the DHCP server configuration file. If no file
|
The path of the DHCP server configuration file. If no file
|
||||||
is specified, a file is generated using the other options.
|
is specified, a file is generated using the other options.
|
||||||
";
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
interfaces = mkOption {
|
interfaces = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
default = ["eth0"];
|
default = ["eth0"];
|
||||||
description = "
|
description = ''
|
||||||
The interfaces on which the DHCP server should listen.
|
The interfaces on which the DHCP server should listen.
|
||||||
";
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
machines = mkOption {
|
machines = mkOption {
|
||||||
|
type = types.listOf (types.submodule machineOpts);
|
||||||
default = [];
|
default = [];
|
||||||
example = [
|
example = [
|
||||||
{ hostName = "foo";
|
{ hostName = "foo";
|
||||||
@ -102,20 +168,31 @@ in
|
|||||||
ipAddress = "192.168.1.11";
|
ipAddress = "192.168.1.11";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
description = "
|
description = ''
|
||||||
A list mapping ethernet addresses to IP addresses for the
|
A list mapping Ethernet addresses to IPv${postfix} addresses for the
|
||||||
DHCP server.
|
DHCP server.
|
||||||
";
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
###### interface
|
||||||
|
|
||||||
|
options = {
|
||||||
|
|
||||||
|
services.dhcpd4 = dhcpConfig "4";
|
||||||
|
services.dhcpd6 = dhcpConfig "6";
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
###### implementation
|
###### implementation
|
||||||
|
|
||||||
config = mkIf config.services.dhcpd.enable {
|
config = mkIf (cfg4.enable || cfg6.enable) {
|
||||||
|
|
||||||
users = {
|
users = {
|
||||||
extraUsers.dhcpd = {
|
extraUsers.dhcpd = {
|
||||||
@ -124,36 +201,7 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.dhcpd =
|
systemd.services = dhcpdService "4" cfg4 // dhcpdService "6" cfg6;
|
||||||
{ description = "DHCP server";
|
|
||||||
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
|
|
||||||
after = [ "network.target" ];
|
|
||||||
|
|
||||||
path = [ pkgs.dhcp ];
|
|
||||||
|
|
||||||
preStart =
|
|
||||||
''
|
|
||||||
mkdir -m 755 -p ${stateDir}
|
|
||||||
|
|
||||||
touch ${stateDir}/dhcpd.leases
|
|
||||||
|
|
||||||
mkdir -m 755 -p /run/dhcpd
|
|
||||||
chown dhcpd /run/dhcpd
|
|
||||||
'';
|
|
||||||
|
|
||||||
serviceConfig =
|
|
||||||
{ ExecStart = "@${pkgs.dhcp}/sbin/dhcpd dhcpd"
|
|
||||||
+ " -pf /run/dhcpd/dhcpd.pid -cf ${configFile}"
|
|
||||||
+ " -lf ${stateDir}/dhcpd.leases -user dhcpd -group nogroup"
|
|
||||||
+ " ${cfg.extraFlags}"
|
|
||||||
+ " ${toString cfg.interfaces}";
|
|
||||||
Restart = "always";
|
|
||||||
Type = "forking";
|
|
||||||
PIDFile = "/run/dhcpd/dhcpd.pid";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -172,13 +172,16 @@ let
|
|||||||
}-j nixos-fw-accept
|
}-j nixos-fw-accept
|
||||||
''}
|
''}
|
||||||
|
|
||||||
|
${optionalString config.networking.enableIPv6 ''
|
||||||
# Accept all ICMPv6 messages except redirects and node
|
# Accept all ICMPv6 messages except redirects and node
|
||||||
# information queries (type 139). See RFC 4890, section
|
# information queries (type 139). See RFC 4890, section
|
||||||
# 4.4.
|
# 4.4.
|
||||||
${optionalString config.networking.enableIPv6 ''
|
|
||||||
ip6tables -A nixos-fw -p icmpv6 --icmpv6-type redirect -j DROP
|
ip6tables -A nixos-fw -p icmpv6 --icmpv6-type redirect -j DROP
|
||||||
ip6tables -A nixos-fw -p icmpv6 --icmpv6-type 139 -j DROP
|
ip6tables -A nixos-fw -p icmpv6 --icmpv6-type 139 -j DROP
|
||||||
ip6tables -A nixos-fw -p icmpv6 -j nixos-fw-accept
|
ip6tables -A nixos-fw -p icmpv6 -j nixos-fw-accept
|
||||||
|
|
||||||
|
# Allow this host to act as a DHCPv6 client
|
||||||
|
ip6tables -A nixos-fw -d fe80::/64 -p udp --dport 546 -j nixos-fw-accept
|
||||||
''}
|
''}
|
||||||
|
|
||||||
${cfg.extraCommands}
|
${cfg.extraCommands}
|
||||||
|
@ -10,29 +10,61 @@ let
|
|||||||
vlanIfs = range 1 (length config.virtualisation.vlans);
|
vlanIfs = range 1 (length config.virtualisation.vlans);
|
||||||
in {
|
in {
|
||||||
virtualisation.vlans = [ 1 2 3 ];
|
virtualisation.vlans = [ 1 2 3 ];
|
||||||
|
boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true;
|
||||||
networking = {
|
networking = {
|
||||||
useDHCP = false;
|
useDHCP = false;
|
||||||
useNetworkd = networkd;
|
useNetworkd = networkd;
|
||||||
firewall.allowPing = true;
|
firewall.allowPing = true;
|
||||||
|
firewall.checkReversePath = true;
|
||||||
|
firewall.allowedUDPPorts = [ 547 ];
|
||||||
interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n:
|
interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n:
|
||||||
nameValuePair "eth${toString n}" {
|
nameValuePair "eth${toString n}" {
|
||||||
ipAddress = "192.168.${toString n}.1";
|
ipAddress = "192.168.${toString n}.1";
|
||||||
prefixLength = 24;
|
prefixLength = 24;
|
||||||
|
ipv6Address = "fd00:1234:5678:${toString n}::1";
|
||||||
|
ipv6PrefixLength = 64;
|
||||||
})));
|
})));
|
||||||
};
|
};
|
||||||
services.dhcpd = {
|
services.dhcpd4 = {
|
||||||
enable = true;
|
enable = true;
|
||||||
interfaces = map (n: "eth${toString n}") vlanIfs;
|
interfaces = map (n: "eth${toString n}") vlanIfs;
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
option subnet-mask 255.255.255.0;
|
authoritative;
|
||||||
'' + flip concatMapStrings vlanIfs (n: ''
|
'' + flip concatMapStrings vlanIfs (n: ''
|
||||||
subnet 192.168.${toString n}.0 netmask 255.255.255.0 {
|
subnet 192.168.${toString n}.0 netmask 255.255.255.0 {
|
||||||
option broadcast-address 192.168.${toString n}.255;
|
|
||||||
option routers 192.168.${toString n}.1;
|
option routers 192.168.${toString n}.1;
|
||||||
|
# XXX: technically it's _not guaranteed_ that IP addresses will be
|
||||||
|
# issued from the first item in range onwards! We assume that in
|
||||||
|
# our tests however.
|
||||||
range 192.168.${toString n}.2 192.168.${toString n}.254;
|
range 192.168.${toString n}.2 192.168.${toString n}.254;
|
||||||
}
|
}
|
||||||
'');
|
'');
|
||||||
};
|
};
|
||||||
|
services.radvd = {
|
||||||
|
enable = true;
|
||||||
|
config = flip concatMapStrings vlanIfs (n: ''
|
||||||
|
interface eth${toString n} {
|
||||||
|
AdvSendAdvert on;
|
||||||
|
AdvManagedFlag on;
|
||||||
|
AdvOtherConfigFlag on;
|
||||||
|
|
||||||
|
prefix fd00:1234:5678:${toString n}::/64 {
|
||||||
|
AdvAutonomous off;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
services.dhcpd6 = {
|
||||||
|
enable = true;
|
||||||
|
interfaces = map (n: "eth${toString n}") vlanIfs;
|
||||||
|
extraConfig = ''
|
||||||
|
authoritative;
|
||||||
|
'' + flip concatMapStrings vlanIfs (n: ''
|
||||||
|
subnet6 fd00:1234:5678:${toString n}::/64 {
|
||||||
|
range6 fd00:1234:5678:${toString n}::2 fd00:1234:5678:${toString n}::2;
|
||||||
|
}
|
||||||
|
'');
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
testCases = {
|
testCases = {
|
||||||
@ -108,8 +140,14 @@ let
|
|||||||
useNetworkd = networkd;
|
useNetworkd = networkd;
|
||||||
firewall.allowPing = true;
|
firewall.allowPing = true;
|
||||||
useDHCP = true;
|
useDHCP = true;
|
||||||
interfaces.eth1.ip4 = mkOverride 0 [ ];
|
interfaces.eth1 = {
|
||||||
interfaces.eth2.ip4 = mkOverride 0 [ ];
|
ip4 = mkOverride 0 [ ];
|
||||||
|
ip6 = mkOverride 0 [ ];
|
||||||
|
};
|
||||||
|
interfaces.eth2 = {
|
||||||
|
ip4 = mkOverride 0 [ ];
|
||||||
|
ip6 = mkOverride 0 [ ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
testScript = { nodes, ... }:
|
testScript = { nodes, ... }:
|
||||||
@ -121,21 +159,31 @@ let
|
|||||||
|
|
||||||
# Wait until we have an ip address on each interface
|
# Wait until we have an ip address on each interface
|
||||||
$client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
|
$client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'");
|
||||||
|
$client->waitUntilSucceeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'");
|
||||||
$client->waitUntilSucceeds("ip addr show dev eth2 | grep -q '192.168.2'");
|
$client->waitUntilSucceeds("ip addr show dev eth2 | grep -q '192.168.2'");
|
||||||
|
$client->waitUntilSucceeds("ip addr show dev eth2 | grep -q 'fd00:1234:5678:2:'");
|
||||||
|
|
||||||
# Test vlan 1
|
# Test vlan 1
|
||||||
$client->waitUntilSucceeds("ping -c 1 192.168.1.1");
|
$client->waitUntilSucceeds("ping -c 1 192.168.1.1");
|
||||||
$client->waitUntilSucceeds("ping -c 1 192.168.1.2");
|
$client->waitUntilSucceeds("ping -c 1 192.168.1.2");
|
||||||
|
$client->waitUntilSucceeds("ping6 -c 1 fd00:1234:5678:1::1");
|
||||||
|
$client->waitUntilSucceeds("ping6 -c 1 fd00:1234:5678:1::2");
|
||||||
|
|
||||||
$router->waitUntilSucceeds("ping -c 1 192.168.1.1");
|
$router->waitUntilSucceeds("ping -c 1 192.168.1.1");
|
||||||
$router->waitUntilSucceeds("ping -c 1 192.168.1.2");
|
$router->waitUntilSucceeds("ping -c 1 192.168.1.2");
|
||||||
|
$router->waitUntilSucceeds("ping6 -c 1 fd00:1234:5678:1::1");
|
||||||
|
$router->waitUntilSucceeds("ping6 -c 1 fd00:1234:5678:1::2");
|
||||||
|
|
||||||
# Test vlan 2
|
# Test vlan 2
|
||||||
$client->waitUntilSucceeds("ping -c 1 192.168.2.1");
|
$client->waitUntilSucceeds("ping -c 1 192.168.2.1");
|
||||||
$client->waitUntilSucceeds("ping -c 1 192.168.2.2");
|
$client->waitUntilSucceeds("ping -c 1 192.168.2.2");
|
||||||
|
$client->waitUntilSucceeds("ping6 -c 1 fd00:1234:5678:2::1");
|
||||||
|
$client->waitUntilSucceeds("ping6 -c 1 fd00:1234:5678:2::2");
|
||||||
|
|
||||||
$router->waitUntilSucceeds("ping -c 1 192.168.2.1");
|
$router->waitUntilSucceeds("ping -c 1 192.168.2.1");
|
||||||
$router->waitUntilSucceeds("ping -c 1 192.168.2.2");
|
$router->waitUntilSucceeds("ping -c 1 192.168.2.2");
|
||||||
|
$router->waitUntilSucceeds("ping6 -c 1 fd00:1234:5678:2::1");
|
||||||
|
$router->waitUntilSucceeds("ping6 -c 1 fd00:1234:5678:2::2");
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
dhcpOneIf = {
|
dhcpOneIf = {
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
{ stdenv, fetchurl, pkgconfig, libdaemon, bison, flex, check }:
|
{ stdenv, fetchurl, pkgconfig, libdaemon, bison, flex, check }:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
name = "radvd-2.13";
|
name = "radvd-${version}";
|
||||||
|
version = "2.15";
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "http://www.litech.org/radvd/dist/${name}.tar.xz";
|
url = "http://www.litech.org/radvd/dist/${name}.tar.xz";
|
||||||
sha256 = "1lzgg6zpizcldb78n5gkykjnpr7sqm4r1xy9bm4ig0chbrink4ka";
|
sha256 = "09spyj4f05rjx21v8vmyqmmj0fz1wx810s63md1vf05hyzd0v8dk";
|
||||||
};
|
};
|
||||||
|
|
||||||
buildInputs = [ pkgconfig libdaemon bison flex check ];
|
nativeBuildInputs = [ pkgconfig bison flex check ];
|
||||||
|
buildInputs = [ libdaemon ];
|
||||||
hardeningEnable = [ "pie" ];
|
|
||||||
|
|
||||||
meta = with stdenv.lib; {
|
meta = with stdenv.lib; {
|
||||||
homepage = http://www.litech.org/radvd/;
|
homepage = http://www.litech.org/radvd/;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user