]> birchwood-abbey.net Git - Institute/commitdiff
Use isc-dhcp-server on Gate again.
authorMatt Birkholz <matt@birchwood-abbey.net>
Tue, 23 Jun 2026 02:04:46 +0000 (20:04 -0600)
committerMatt Birkholz <matt@birchwood-abbey.net>
Wed, 24 Jun 2026 16:38:01 +0000 (10:38 -0600)
Punt SystemD NetworkD's built-in server, which stopped recognizing
DHCPServerStaticLease.

README.org
private/test-gate-prep
roles_t/gate/handlers/main.yml
roles_t/gate/tasks/main.yml
roles_t/gate/templates/dhcpd.conf [new file with mode: 0644]
roles_t/gate/templates/wild.network [deleted file]

index c83c41e11ec7cbcb45f21ea2030bec63419ab59e..3a8c11e1773e5dc9fe3ccf356bbc027eb6ab2cf4 100644 (file)
@@ -1181,9 +1181,9 @@ cable modem and installed them as shown below.
 # A similar list of packages is installed on "The Test Gate Machine".
 # That list should be kept in sync with this list!
 
-: $ sudo apt install systemd-resolved unattended-upgrades \
-: _                  ufw postfix wireguard lm-sensors \
-: _                  nagios-nrpe-server munin-node emacs
+: $ sudo apt install wireguard systemd-resolved unattended-upgrades \
+: _                  ufw postfix lm-sensors nagios-nrpe-server \
+: _                  munin-node emacs isc-dhcp-server
 
 Manual installation of Postfix prompted for configuration type and
 mail name.  The answers given are listed here.
@@ -4954,8 +4954,7 @@ subnet is connected to Gate via a separate physical interface.  To
 accommodate the wild ones without re-configuring them, the institute
 attempts to look like an up-link, e.g. a cable modem.  A wild one is
 expected to chirp for DHCP service and use the private subnet address
-in its lease.  Thus Gate's ~wild~ interface configuration enables the
-built-in DHCP server and lists the authorized lessees.
+in its lease.
 
 The wild ones are not expected to number in the dozens, so they are
 simply a list of hashes in [[file:private/vars.yml][=private/vars.yml=]], as in the example code
@@ -4971,8 +4970,7 @@ wild_ones:
 
 As with the ~lan~ interface, this interface is named ~wild~ and
 configured by =10-wild.link= and =10-wild.network= files in
-=/etc/systemd/network/=.  The latter is generated from the hashes in
-~wild_ones~ and the =wild.network= template file.
+=/etc/systemd/network/=.
 
 #+CAPTION: [[file:roles_t/gate/tasks/main.yml][=roles_t/gate/tasks/main.yml=]]
 #+BEGIN_SRC conf :tangle roles_t/gate/tasks/main.yml
@@ -4989,33 +4987,116 @@ configured by =10-wild.link= and =10-wild.network= files in
 
 - name: Install 10-wild.network.
   become: yes
-  template:
-    src: wild.network
+  copy:
+    content: |
+      [Match]
+      MACAddress={{ gate_wild_mac }}
+
+      [Network]
+      Address={{ gate_wild_addr_cidr }}
     dest: /etc/systemd/network/10-wild.network
   notify: Reload networkd.
 #+END_SRC
 
-#+CAPTION: [[file:roles_t/gate/templates/wild.network][=roles_t/gate/templates/wild.network=]]
-#+BEGIN_SRC conf :tangle roles_t/gate/templates/wild.network :mkdirp yes
-[Match]
-MACAddress={{ gate_wild_mac }}
+*** Configure DHCP For Gate's ~wild~ Interface
 
-[Network]
-Address={{ gate_wild_addr_cidr }}
-DHCPServer=yes
+Gate runs ISC's DHCP daemon to serve the ~wild~ interface.  It is
+configured to listen only on that interface and recognize only known
+clients, providing each with an IP address and customary network
+parameters (default route, name server, etc.), much as was done on
+Core for the private Ethernet.
+
+Gate once used SystemD NetworkD's built-in DHCP server, and then one
+day it stopped working, producing error messages about the unknown
+directive ~DHCPServerStaticLease~, handing out weird IP addresses,
+making the IoT appliances unreachable.
+
+The template configuration file, [[file:private/gate-dhcpd.conf][=dhcpd.conf=]], unlike
+[[file:private/core-dhcpd.conf][=private/core-dhcpd.conf=]], does not need RFC3442 (Classless static
+routes).  The wild ones need know /nothing/ about the private
+network(s).
+
+#+CAPTION: [[file:roles_t/gate/templates/dhcpd.conf][=roles_t/gate/templates/dhcpd.conf=]]
+#+BEGIN_SRC conf :tangle roles_t/gate/templates/dhcpd.conf :mkdirp yes
+default-lease-time 3600;
+max-lease-time 7200;
+
+ddns-update-style none;
+
+authoritative;
+
+log-facility daemon;
 
-[DHCPServer]
-DNS={{ gate_wild_addr }}
-EmitDNS=yes
+subnet {{ wild_net }} netmask {{ wild_net_mask }} {
+  option subnet-mask {{ wild_net_mask }};
+  option broadcast-address {{ wild_net_broadcast }};
+  option routers {{ gate_wild_addr }};
+  option domain-name-servers {{ gate_wild_addr }};
+}
 {% for wild in wild_ones %}
 
-# {{ wild.name }}
-[DHCPServerStaticLease]
-MACAddress={{ wild.MAC }}
-Address={{ wild_net_cidr |ansible.utils.ipaddr(wild.num) }}
+host {{ wild.name }} {
+  hardware ethernet {{ wild.MAC }};
+  fixed-address {{ wild_net_cidr
+                   |ansible.utils.ipaddr(wild.num)
+                   |ansible.utils.ipaddr('address') }};
+}
 {% endfor %}
 #+END_SRC
 
+Installation and configuration of the DHCP daemon follows.  Note that
+the daemon listens /only/ on the ~wild~ network interface.  Also note
+that there is no longer an added ~Requires~ dependency, in deference
+to the ~Wants~ dependency generated by ~systemd-sysv-generator~.
+Presumably the (new?) ~Wants~ dependencies alone will avoid the
+previous intermittent failures where the ~wild~ interface had no IPv4
+addresses (or did not exist at all?).
+
+#+CAPTION: [[file:roles_t/gate/tasks/main.yml][=roles_t/gate/tasks/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/gate/tasks/main.yml
+- name: Install DHCP server.
+  become: yes
+  apt: pkg=isc-dhcp-server
+
+- name: Configure DHCP interface.
+  become: yes
+  lineinfile:
+    path: /etc/default/isc-dhcp-server
+    line: INTERFACESv4="wild"
+    regexp: ^INTERFACESv4=
+  notify: Restart DHCP server.
+
+- name: Configure DHCP subnet.
+  become: yes
+  template:
+    src: dhcpd.conf
+    dest: /etc/dhcp/dhcpd.conf
+  notify: Restart DHCP server.
+
+- name: Start DHCP server.
+  become: yes
+  systemd:
+    service: isc-dhcp-server
+    state: started
+  tags: actualizer
+
+- name: Enable DHCP server.
+  become: yes
+  systemd:
+    service: isc-dhcp-server
+    enabled: yes
+#+END_SRC
+
+#+CAPTION: [[file:roles_t/gate/handlers/main.yml][=roles_t/gate/handlers/main.yml=]]
+#+BEGIN_SRC conf :tangle roles_t/gate/handlers/main.yml
+- name: Restart DHCP server.
+  become: yes
+  systemd:
+    service: isc-dhcp-server
+    state: restarted
+  tags: actualizer
+#+END_SRC
+
 *** Gate's ~isp~ Interface
 
 The interface to the campus ISP is named ~isp~ and configured by
@@ -5126,11 +5207,6 @@ listener" listen there.  That stub should not read =/etc/hosts= lest
 
 #+CAPTION: [[file:roles_t/gate/handlers/main.yml][=roles_t/gate/handlers/main.yml=]]
 #+BEGIN_SRC conf :tangle roles_t/gate/handlers/main.yml
-- name: Reload Systemd.
-  become: yes
-  systemd:
-    daemon-reload: yes
-
 - name: Restart Systemd resolved.
   become: yes
   systemd:
@@ -7466,8 +7542,8 @@ The script starts by installing additional software packages.
 #!/bin/bash -e
 
 sudo apt install wireguard systemd-resolved unattended-upgrades \
-                postfix ufw lm-sensors nagios-nrpe-server \
-                munin-node emacs
+                ufw postfix lm-sensors nagios-nrpe-server \
+                munin-node emacs isc-dhcp-server
 #+END_SRC
 
 # A similar list of packages is installed on "The Gate Machine".
index be042e3ee062fa9189a2f7cc07c52f5afea4b89c..27efc29d43a1094175740adf5c0f747e6fc8b664 100755 (executable)
@@ -1,8 +1,8 @@
 #!/bin/bash -e
 
 sudo apt install wireguard systemd-resolved unattended-upgrades \
-                postfix ufw lm-sensors nagios-nrpe-server \
-                munin-node emacs
+                ufw postfix lm-sensors nagios-nrpe-server \
+                munin-node emacs isc-dhcp-server
 
 ( umask 377
   echo "yOBdLbXh6KBwYQvvb5mhiku8Fxkqc5Cdyz6gNgjc/2U=" \
index 11cd69a4bfa997cd179a25fe5374373a481d6ab6..2d962be48569822dbdf595489965377f3bb670be 100644 (file)
@@ -4,10 +4,12 @@
   command: networkctl reload
   tags: actualizer
 
-- name: Reload Systemd.
+- name: Restart DHCP server.
   become: yes
   systemd:
-    daemon-reload: yes
+    service: isc-dhcp-server
+    state: restarted
+  tags: actualizer
 
 - name: Restart Systemd resolved.
   become: yes
index 05bced746c6230353fb7b16220eac15c3041844c..fef521b0a7ec082187260f1acab992b0752520ad 100644 (file)
 
 - name: Install 10-wild.network.
   become: yes
-  template:
-    src: wild.network
+  copy:
+    content: |
+      [Match]
+      MACAddress={{ gate_wild_mac }}
+
+      [Network]
+      Address={{ gate_wild_addr_cidr }}
     dest: /etc/systemd/network/10-wild.network
   notify: Reload networkd.
 
+- name: Install DHCP server.
+  become: yes
+  apt: pkg=isc-dhcp-server
+
+- name: Configure DHCP interface.
+  become: yes
+  lineinfile:
+    path: /etc/default/isc-dhcp-server
+    line: INTERFACESv4="wild"
+    regexp: ^INTERFACESv4=
+  notify: Restart DHCP server.
+
+- name: Configure DHCP subnet.
+  become: yes
+  template:
+    src: dhcpd.conf
+    dest: /etc/dhcp/dhcpd.conf
+  notify: Restart DHCP server.
+
+- name: Start DHCP server.
+  become: yes
+  systemd:
+    service: isc-dhcp-server
+    state: started
+  tags: actualizer
+
+- name: Enable DHCP server.
+  become: yes
+  systemd:
+    service: isc-dhcp-server
+    enabled: yes
+
 - name: Install 10-isp.link.
   become: yes
   copy:
diff --git a/roles_t/gate/templates/dhcpd.conf b/roles_t/gate/templates/dhcpd.conf
new file mode 100644 (file)
index 0000000..cbe0126
--- /dev/null
@@ -0,0 +1,24 @@
+default-lease-time 3600;
+max-lease-time 7200;
+
+ddns-update-style none;
+
+authoritative;
+
+log-facility daemon;
+
+subnet {{ wild_net }} netmask {{ wild_net_mask }} {
+  option subnet-mask {{ wild_net_mask }};
+  option broadcast-address {{ wild_net_broadcast }};
+  option routers {{ gate_wild_addr }};
+  option domain-name-servers {{ gate_wild_addr }};
+}
+{% for wild in wild_ones %}
+
+host {{ wild.name }} {
+  hardware ethernet {{ wild.MAC }};
+  fixed-address {{ wild_net_cidr
+                   |ansible.utils.ipaddr(wild.num)
+                   |ansible.utils.ipaddr('address') }};
+}
+{% endfor %}
diff --git a/roles_t/gate/templates/wild.network b/roles_t/gate/templates/wild.network
deleted file mode 100644 (file)
index 87b9151..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-[Match]
-MACAddress={{ gate_wild_mac }}
-
-[Network]
-Address={{ gate_wild_addr_cidr }}
-DHCPServer=yes
-
-[DHCPServer]
-DNS={{ gate_wild_addr }}
-EmitDNS=yes
-{% for wild in wild_ones %}
-
-# {{ wild.name }}
-[DHCPServerStaticLease]
-MACAddress={{ wild.MAC }}
-Address={{ wild_net_cidr |ansible.utils.ipaddr(wild.num) }}
-{% endfor %}