Allow and deny lists per subnet; every option of a DHCP message in words

- A subnet is a deny-list subnet (the default: everyone not denied) or
  an allow-list subnet (only clients allowed or with a reservation);
  the deny list counts in both. Entries are MAC addresses, prefixes
  (aa:bb:cc:*) or client IDs. A refused client gets no answer (DENIED
  in the activity log, with an Allow button) or a NAK on renewal.
  steward access, the subnet's Access tab. Schema migration 7.
- The activity log keeps each message's header fields and options,
  decoded into words (dhcp4.Describe): the parameter request list by
  name, client IDs, lease times. ▸ on an Activity row, steward
  activity show N / --details, GET /events/{id}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
abrown38andClaude Opus 5.5 committed 2026-10-18 20:27:51 +01:00
1 parent b3c8329ae8
commit 3ad2f981d4
30 files changed
+1092 -37

No files matched your search

+37 -5
View File
@@ -82,6 +82,18 @@ one. An option Steward doesn't know: `--option 224:string=hello`.
| `reservation enable\|disable RES` | use a reservation, or keep it but ignore it |
| `reservation delete RES` | |
### access
| Command | |
|---|---|
| `access show SUBNET` | the subnet's mode and its allow and deny lists |
| `access mode SUBNET deny-list\|allow-list` | answer every client not denied, or only the allowed (and reserved) |
| `access allow SUBNET ENTRY... [--comment C]` | add to the allow list (`aa:bb:cc:dd:ee:ff`, `aa:bb:cc:*` or `id HEX`); an entry it has gets the new comment |
| `access deny SUBNET ENTRY... [--comment C]` | add to the deny list |
| `access remove SUBNET ENTRY...` | take off both lists |
See [subnets.md](subnets.md#access-allow-and-deny-lists).
### lease
| Command | |
@@ -93,19 +105,39 @@ one. An option Steward doesn't know: `--option 224:string=hello`.
### activity
`steward activity [--mac MAC] [--subnet SUBNET] [--interface I] [--limit N] [-f]`:
`steward activity [--mac MAC] [--subnet SUBNET] [--interface I] [--limit N] [-d] [-f]`:
the latest DHCP messages, received and sent, oldest first. `--subnet`
takes an ID, name or prefix; a message without an address (a DISCOVER,
"no address") shows for every subnet on its interface. `-f` keeps
watching, which is useful while a device tries to get an address:
```
11:02:13.120 eth0 DHCPDISCOVER 3c:22:fb:11:22:33 - adams-macbook
11:02:13.622 eth0 DHCPOFFER 3c:22:fb:11:22:33 10.0.10.150 adams-macbook
11:02:13.630 eth0 DHCPREQUEST 3c:22:fb:11:22:33 10.0.10.150 adams-macbook
11:02:13.631 eth0 DHCPACK 3c:22:fb:11:22:33 10.0.10.150 adams-macbook
#1042 11:02:13.120 eth0 DHCPDISCOVER 3c:22:fb:11:22:33 - adams-macbook
#1043 11:02:13.622 eth0 DHCPOFFER 3c:22:fb:11:22:33 10.0.10.150 adams-macbook
#1044 11:02:13.630 eth0 DHCPREQUEST 3c:22:fb:11:22:33 10.0.10.150 adams-macbook
#1045 11:02:13.631 eth0 DHCPACK 3c:22:fb:11:22:33 10.0.10.150 adams-macbook
```
Each line starts with the message's number. `-d` (`--details`) adds every
field and option of each message in words, and `steward activity show N`
shows one: what the client asked for (its parameter request list, by
name), its client identifier and host name, and what Steward sent back
(lease time, routers, DNS servers...):
```
$ steward activity show 1042
#1042 DHCPDISCOVER on eth0 at 2026-10-18 11:02:13.120, received from the client
transaction ID: 0x3a1c99f0
client hardware address: 3c:22:fb:11:22:33
flags: broadcast (the client wants replies broadcast)
option 53 message-type: DHCPDISCOVER
option 61 client-identifier: 01:3c:22:fb:11:22:33 (type 1: the MAC address 3c:22:fb:11:22:33)
option 55 parameter-request-list: subnet-mask (1), routers (3), domain-name-servers (6), domain-name (15), v4-captive-portal (114)
option 12 host-name: adams-macbook
```
In the web UI, ▸ on an Activity row opens the same.
`NO ADDRESS` means the pools on that interface are full, and `CONFLICT`
an address that answered the ping check. A `DHCPNAK` says why it was
sent.