Skip to main content

dhcpctl

Version Python versions License: MIT Docs CI

One interface to DHCP servers: arm a reservation for a client on dnsmasq, ISC Kea, ISC dhcpd or Windows DHCP, then remove it or keep it without its boot options. A server is a URI: its scheme picks the backend and its query says how to reach it. The options to serve belong to each reservation. Documentation: https://jose-pr.github.io/dhcpctl/.

Features

  • Four servers, one call — add, remove, complete on dnsmasq (files, local or over sftp://), Kea (control agent), dhcpd (OMAPI) and Windows DHCP (PowerShell cmdlets or netsh, locally, over ssh or WinRM).
  • pydhcp's lease — what a client is served is a pydhcp DHCPLease: its address, its DHCPOptions named by pydhcp's registry (router, dns, option-<n>) or an alias, each value read by its pydhcp codec before any server sees it, and the BOOTP header fields (next-server, file); each backend translates them, and backend-native text in a reservation's extras rides through untouched.
  • Conditions — options served only to clients that match a test (the iPXE chainload), as a Windows policy, a dhcpd if or group, or a Kea client class; a backend that cannot express one refuses rather than arming without it, and hands over the server-side recipe when it lacks the rights to create it.
  • Completion that does not reinstall — keep a finished client's reservation and replace only its boot options.
  • Values are data, never source — dhcpd statements are escaped, Windows scripts get their parameters as a JSON payload, netsh arguments stay array elements.
  • Nothing required — each backend's library is an extra, imported only when its scheme is used; secrets come from the URI or the caller, and a password is masked wherever a server is shown.
  • Reservations as documents — Reservation.to_mapping / from_mapping and to_text / from_text (JSON, YAML, TOML, INI) round-trip a reservation through pydhcp's own option form.
  • Pluggable — a backend is a DHCPServer subclass registered for a scheme, directly or through the dhcpctl.backends entry point.

Installation

pip install pydhcpctl

The distribution is pydhcpctl; the import package is dhcpctl.

Scheme Server Install
dnsmasq:// dnsmasq nothing locally; pydhcpctl[ssh] for sftp:// paths
kea://, keas:// ISC Kea control agent pydhcpctl[kea] (requests)
dhcpd:// ISC dhcpd over OMAPI pydhcpctl[dhcpd] (pypureomapi)
windhcp:// Windows DHCP nothing locally; pydhcpctl[ssh] over ssh, pydhcpctl[winrm] over WinRM

pydhcpctl[formats] adds YAML, TOML and INI to Reservation.to_text / from_text (JSON needs nothing), and pydhcpctl[cli] the dhcpctl command.

Python 3.9 or later.

Usage

import dhcpctl
from ipaddress import ip_network

from netimps import MACAddress

server = dhcpctl.connect("kea://kea01:8000/?service=dhcp4")  # how to reach it, nothing else

# Options by name, and the BOOTP header fields beside them (not options).
lease = server.codes.lease(
    {"router": "10.0.0.1", "file": "undionly.kpxe", "next-server": "10.0.0.2"}
)
reservation = dhcpctl.Reservation(
    target=dhcpctl.Target("web01", mac=MACAddress("aa:bb:cc:dd:ee:ff")),
    scope=dhcpctl.Scope("lan", network=ip_network("10.0.0.0/24")),
    lease=lease.replace(ip="10.0.0.10"),
    completion=dhcpctl.Completion(keep=True),  # keep the address when done
)

server.add(reservation)       # arm
server.complete(reservation)  # finished: keep the entry, drop its boot options

A condition serves different options to clients that match a test:

import dataclasses

conditions = dhcpctl.parse_conditions(
    {"ipxe": {"match": {"user-class": "iPXE"}, "options": {"file": "boot.ipxe"}}}
)
server.add(dataclasses.replace(reservation, conditions=conditions))
print(server.condition_recipe(reservation, conditions["ipxe"]))  # what an admin applies

A secret is the URI's when it carries one, else the caller's, asked for only when needed — so it can stay out of a URI that ends up in config or logs:

server = dhcpctl.connect(
    "windhcp://dhcp01/?transport=winrm", secrets={"user": "svc", "password": "..."}
)

Command line

pip install pydhcpctl[cli] adds the dhcpctl command (also python -m dhcpctl). A reservation is given by flags, or as a document with --from (.json, .yaml, .toml, .ini, or - for JSON on standard input), which can also carry conditions and a completion:

# What arming web01 would send, contacting nothing:
dhcpctl render 'dhcpd://dhcp01/' -n web01 -m aa:bb:cc:dd:ee:ff --ip 10.0.0.10 \
    -o router=10.0.0.1 -o file=undionly.kpxe
dhcpctl add 'kea://kea01/?target=memory' --from web01.json   # arm (or re-arm)
dhcpctl complete 'kea://kea01/?target=memory' --from web01.json --keep
dhcpctl remove 'windhcp://dhcp01/?transport=winrm' -n web01 -m aa:bb:cc:dd:ee:ff
dhcpctl recipe 'windhcp://dhcp01/' --from web01.json         # what an admin sets up once
dhcpctl backends --json

-o name=value is an option or header field; a comma makes a list (dns=10.0.0.53,10.0.0.54) and json: a JSON value (lease-time=json:600). Secrets come from the environment, never a flag: DHCPCTL_USER, DHCPCTL_PASSWORD, DHCPCTL_KEYNAME, DHCPCTL_OMAPI_KEY. Exit status 0 is done, 1 the server refused or could not be reached, 2 the invocation or the reservation was wrong.

Writing a backend

class Recorder(dhcpctl.DHCPServer):
    def add(self, reservation): ...
    def remove(self, reservation): ...

dhcpctl.register_backend("recorder", Recorder)
dhcpctl.connect("recorder://anything")

or declare it in your package's metadata:

[project.entry-points."dhcpctl.backends"]
recorder = "mypkg.dhcp:Recorder"

A backend is done when it passes the contract the shipped ones pass, which talks to no server (it needs pytest, and the backend to implement render):

from dhcpctl.testing import BackendContract

class TestRecorder(BackendContract):
    uri = "recorder://anything"

License

MIT

Metadata

Release files for pydhcpctl 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pydhcpctl 0.1.1
File Size Uploaded Provenance
pydhcpctl-0.1.1.tar.gz 133.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pydhcpctl 0.1.1
File Interpreter ABI Platform
pydhcpctl-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 216.5 kB

Release files / pydhcpctl-0.1.1.tar.gz

Download URL pydhcpctl-0.1.1.tar.gz
Size 133.1 kB
Tags Source
SHA-256 checksum
How to use checksums
3571c9e5f553ce577494771ff8b5dd8c7586c68cad359af6718d4230b6a3e254
BLAKE2b-256 checksum
How to use checksums
5f96766f5056183d814ad7b7fb450124dab400e7e8f50bb14921d953dd94f2e9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Release files / pydhcpctl-0.1.1-py3-none-any.whl

Download URL pydhcpctl-0.1.1-py3-none-any.whl
Size 83.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c16350eeb0b01ef1a1856b9c1165e13e0347c4096ba45817fe7a5ae117f7c057
BLAKE2b-256 checksum
How to use checksums
fc89ee31cd4e6c53c7b145e3cc031975b1c825841f6986122c0c2acddc13cdee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Security for pydhcpctl 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pydhcpctl-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page