1# This test verifies DHCPv4 interaction between a client and a router.
2# For successful DHCP allocations a dynamic update request is sent
3# towards a nameserver to allocate a name in the lan.nixos.test zone.
4# We then verify whether client and router can ping each other, and
5# that the nameserver can resolve the clients fqdn to the correct IP
6# address.
7
8{
9 pkgs,
10 lib,
11 ...
12}:
13{
14 meta.maintainers = with lib.maintainers; [ hexa ];
15
16 name = "kea";
17
18 nodes = {
19 router =
20 { config, pkgs, ... }:
21 {
22 virtualisation.vlans = [ 1 ];
23
24 networking = {
25 useDHCP = false;
26 firewall.allowedUDPPorts = [ 67 ];
27 };
28
29 systemd.network = {
30 enable = true;
31 networks = {
32 "01-eth1" = {
33 name = "eth1";
34 networkConfig = {
35 Address = "10.0.0.1/29";
36 };
37 };
38 };
39 };
40
41 services.kea.dhcp4 = {
42 enable = true;
43 settings = {
44 valid-lifetime = 3600;
45 renew-timer = 900;
46 rebind-timer = 1800;
47
48 lease-database = {
49 type = "memfile";
50 persist = true;
51 name = "/var/lib/kea/dhcp4.leases";
52 };
53
54 control-socket = {
55 socket-type = "unix";
56 socket-name = "/run/kea/dhcp4.sock";
57 };
58
59 interfaces-config = {
60 dhcp-socket-type = "raw";
61 interfaces = [
62 "eth1"
63 ];
64 };
65
66 subnet4 = [
67 {
68 id = 1;
69 subnet = "10.0.0.0/29";
70 pools = [
71 {
72 pool = "10.0.0.3 - 10.0.0.3";
73 }
74 ];
75 }
76 ];
77
78 # Enable communication between dhcp4 and a local dhcp-ddns
79 # instance.
80 # https://kea.readthedocs.io/en/kea-2.2.0/arm/dhcp4-srv.html#ddns-for-dhcpv4
81 dhcp-ddns = {
82 enable-updates = true;
83 };
84
85 ddns-send-updates = true;
86 ddns-qualifying-suffix = "lan.nixos.test.";
87 };
88 };
89
90 services.kea.dhcp-ddns = {
91 enable = true;
92 settings = {
93 forward-ddns = {
94 # Configure updates of a forward zone named `lan.nixos.test`
95 # hosted at the nameserver at 10.0.0.2
96 # https://kea.readthedocs.io/en/kea-2.2.0/arm/ddns.html#adding-forward-dns-servers
97 ddns-domains = [
98 {
99 name = "lan.nixos.test.";
100 # Use a TSIG key in production!
101 key-name = "";
102 dns-servers = [
103 {
104 ip-address = "10.0.0.2";
105 port = 53;
106 }
107 ];
108 }
109 ];
110 };
111 };
112 };
113
114 services.kea.ctrl-agent = {
115 enable = true;
116 settings = {
117 http-host = "127.0.0.1";
118 http-port = 8000;
119 control-sockets.dhcp4 = {
120 socket-type = "unix";
121 socket-name = "/run/kea/dhcp4.sock";
122 };
123 };
124 };
125
126 services.prometheus.exporters.kea = {
127 enable = true;
128 controlSocketPaths = [
129 "http://127.0.0.1:8000"
130 ];
131 };
132 };
133
134 nameserver =
135 { config, pkgs, ... }:
136 {
137 virtualisation.vlans = [ 1 ];
138
139 networking = {
140 useDHCP = false;
141 firewall.allowedUDPPorts = [ 53 ];
142 };
143
144 systemd.network = {
145 enable = true;
146 networks = {
147 "01-eth1" = {
148 name = "eth1";
149 networkConfig = {
150 Address = "10.0.0.2/29";
151 };
152 };
153 };
154 };
155
156 services.resolved.enable = false;
157
158 # Set up an authoritative nameserver, serving the `lan.nixos.test`
159 # zone and configure an ACL that allows dynamic updates from
160 # the router's ip address.
161 # This ACL is likely insufficient for production usage. Please
162 # use TSIG keys.
163 services.knot =
164 let
165 zone = pkgs.writeTextDir "lan.nixos.test.zone" ''
166 @ SOA ns.nixos.test nox.nixos.test 0 86400 7200 3600000 172800
167 @ NS nameserver
168 nameserver A 10.0.0.3
169 router A 10.0.0.1
170 '';
171 zonesDir = pkgs.buildEnv {
172 name = "knot-zones";
173 paths = [ zone ];
174 };
175 in
176 {
177 enable = true;
178 extraArgs = [
179 "-v"
180 ];
181 settings = {
182 server.listen = [
183 "0.0.0.0@53"
184 ];
185
186 log.syslog.any = "info";
187
188 acl.dhcp_ddns = {
189 address = "10.0.0.1";
190 action = "update";
191 };
192
193 template.default = {
194 storage = zonesDir;
195 zonefile-sync = "-1";
196 zonefile-load = "difference-no-serial";
197 journal-content = "all";
198 };
199
200 zone."lan.nixos.test" = {
201 file = "lan.nixos.test.zone";
202 acl = [
203 "dhcp_ddns"
204 ];
205 };
206 };
207 };
208
209 };
210
211 client =
212 { config, pkgs, ... }:
213 {
214 virtualisation.vlans = [ 1 ];
215 systemd.services.systemd-networkd.environment.SYSTEMD_LOG_LEVEL = "debug";
216 networking = {
217 useNetworkd = true;
218 useDHCP = false;
219 firewall.enable = false;
220 interfaces.eth1.useDHCP = true;
221 };
222 };
223 };
224 testScript =
225 { ... }:
226 ''
227 start_all()
228 router.wait_for_unit("kea-dhcp4-server.service")
229 client.systemctl("start systemd-networkd-wait-online.service")
230 client.wait_for_unit("systemd-networkd-wait-online.service")
231 client.wait_until_succeeds("ping -c 5 10.0.0.1")
232 router.wait_until_succeeds("ping -c 5 10.0.0.3")
233 nameserver.wait_until_succeeds("kdig +short client.lan.nixos.test @10.0.0.2 | grep -q 10.0.0.3")
234 router.log(router.execute("curl 127.0.0.1:9547")[1])
235 router.succeed("curl --no-buffer 127.0.0.1:9547 | grep -qE '^kea_dhcp4_addresses_assigned_total.*1.0$'")
236 '';
237}