Files
abrown38andClaude Opus 5.5 3c0808591f Steward 0.1.0 (in development): a DHCPv4 server with a web UI, API and CLI
Subnets served per interface, pools, reservations, options at three
levels, leases in SQLite saved before the ACK, ping and decline conflict
checks, validated changes with history and undo, users and tokens, an
audit log, a Kea importer, a sandboxed systemd unit and Debian packages.
Tested with real udhcpc and dhcpcd clients in Docker (scripts/e2e.sh).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:14:07 +01:00

66 lines
3.6 KiB
Markdown

# Validation
Every change is checked as a whole configuration before it is saved. An
**error** stops the change; a **warning** is reported with it, and stays
on the dashboard and in `steward status` until fixed. Each problem has a
stable code, shown by the CLI as `[code]` and in the API as
`problems[].code`. `stewardd check` runs the checks on the saved
configuration.
The warnings marked *host* compare the configuration with this machine's
interfaces. They come from stewardd, not from a configuration on its own.
## Settings
| Code | | When |
|---|---|---|
| `lease_time_range` | error | a lease time (settings or subnet) under 1 minute or over 365 days |
| `ping_timeout_range` | error | the ping timeout isn't 50 to 5000 ms |
| `decline_hold_range` | error | the decline hold isn't 1 minute to 30 days |
## Options
These apply to options anywhere (settings, subnets, reservations).
| Code | | When |
|---|---|---|
| `option_code` | error | a number outside 1 to 254 |
| `option_reserved` | error | an option Steward sets itself, such as the lease time or the subnet mask ([options.md](options.md#options-steward-sets-itself)) |
| `option_duplicate` | error | the same option twice in one place |
| `option_invalid` | error | a value that doesn't fit the option's type (`dns.example` for `domain-name-servers`) |
## Subnets
| Code | | When |
|---|---|---|
| `subnet_prefix` | error | not an IPv4 network, or host bits set (`10.0.10.5/24`; the message gives the network) |
| `subnet_size` | error | shorter than /8 or longer than /30 |
| `subnet_overlap` | error | it overlaps another subnet |
| `subnet_name` | error | the name has spaces, slashes or commas |
| `subnet_name_taken` | error | another subnet has the name (names are compared without case) |
| `subnet_interface_missing` | error | no interface given |
| `subnet_interface_name` | error | not an interface name (over 15 characters, or spaces, `/` or `:`) |
| `subnet_no_pools` | warning | no pools: only clients with a reservation get addresses |
| `pool_invalid` | error | a pool that ends before it starts |
| `pool_outside_subnet` | error | a pool not inside the subnet |
| `pool_network_address` | error | a pool with the network or broadcast address |
| `pool_overlap` | error | two pools overlap |
| `router_outside_subnet` | warning | a `routers` address outside the subnet: clients can't reach it |
| `router_in_pool` | warning | a `routers` address inside a pool. The ping check keeps it from being handed out while it answers, but take it out of the pool |
| `interface_unknown` | warning, host | the interface doesn't exist on this machine. It is served once it appears |
| `interface_no_address` | warning, host | the interface has no address in the subnet. Clients renew with that address, so give it one |
| `pool_includes_server` | warning, host | a pool has the server's own address. It is never handed out, but take it out of the pool |
## Reservations
| Code | | When |
|---|---|---|
| `reservation_no_client` | error | neither a MAC address nor a client identifier |
| `reservation_ip` | error | not an IPv4 address |
| `reservation_no_subnet` | error | the address is in no subnet; add the subnet first |
| `reservation_network_address` | error | the network or broadcast address of its subnet |
| `reservation_ip_taken` | error | the address is reserved already |
| `reservation_client_taken` | error | the client has a reservation in this subnet already (one per subnet; a device on two VLANs may have one in each) |
| `reservation_hostname` | error | not a host name (letters, digits and `-`, labels up to 63 characters) |
| `reservation_server_address` | warning, host | the server's own address |