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