pydhcp 0.2.1rc1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. pydhcp-0.2.1rc1/.gitignore +20 -0
  2. pydhcp-0.2.1rc1/CHANGELOG.md +71 -0
  3. pydhcp-0.2.1rc1/LICENSE +21 -0
  4. pydhcp-0.2.1rc1/PKG-INFO +116 -0
  5. pydhcp-0.2.1rc1/README.md +82 -0
  6. pydhcp-0.2.1rc1/benchmarks/README.md +25 -0
  7. pydhcp-0.2.1rc1/benchmarks/bench_options.py +58 -0
  8. pydhcp-0.2.1rc1/benchmarks/bench_parse.py +77 -0
  9. pydhcp-0.2.1rc1/docs/api.md +23 -0
  10. pydhcp-0.2.1rc1/docs/deployment.md +45 -0
  11. pydhcp-0.2.1rc1/docs/examples.md +50 -0
  12. pydhcp-0.2.1rc1/docs/faq.md +13 -0
  13. pydhcp-0.2.1rc1/docs/index.md +44 -0
  14. pydhcp-0.2.1rc1/docs/options.md +103 -0
  15. pydhcp-0.2.1rc1/docs/troubleshooting.md +41 -0
  16. pydhcp-0.2.1rc1/examples/dhcpd.py +48 -0
  17. pydhcp-0.2.1rc1/examples/listener.py +18 -0
  18. pydhcp-0.2.1rc1/mkdocs.yml +46 -0
  19. pydhcp-0.2.1rc1/pyproject.toml +53 -0
  20. pydhcp-0.2.1rc1/src/pydhcp/__init__.py +107 -0
  21. pydhcp-0.2.1rc1/src/pydhcp/_options.py +50 -0
  22. pydhcp-0.2.1rc1/src/pydhcp/_platform_utils.py +503 -0
  23. pydhcp-0.2.1rc1/src/pydhcp/_utils.py +24 -0
  24. pydhcp-0.2.1rc1/src/pydhcp/cli.py +108 -0
  25. pydhcp-0.2.1rc1/src/pydhcp/config.py +16 -0
  26. pydhcp-0.2.1rc1/src/pydhcp/constants.py +9 -0
  27. pydhcp-0.2.1rc1/src/pydhcp/enum/__init__.py +56 -0
  28. pydhcp-0.2.1rc1/src/pydhcp/enum/_optioncode_types.py +116 -0
  29. pydhcp-0.2.1rc1/src/pydhcp/enum/messagetype.py +89 -0
  30. pydhcp-0.2.1rc1/src/pydhcp/enum/optioncode.py +844 -0
  31. pydhcp-0.2.1rc1/src/pydhcp/lease.py +158 -0
  32. pydhcp-0.2.1rc1/src/pydhcp/listener.py +437 -0
  33. pydhcp-0.2.1rc1/src/pydhcp/log.py +2 -0
  34. pydhcp-0.2.1rc1/src/pydhcp/message.py +315 -0
  35. pydhcp-0.2.1rc1/src/pydhcp/metrics.py +17 -0
  36. pydhcp-0.2.1rc1/src/pydhcp/netutils.py +140 -0
  37. pydhcp-0.2.1rc1/src/pydhcp/options.py +217 -0
  38. pydhcp-0.2.1rc1/src/pydhcp/optiontype.py +1074 -0
  39. pydhcp-0.2.1rc1/src/pydhcp/py.typed +1 -0
  40. pydhcp-0.2.1rc1/src/pydhcp/server.py +297 -0
  41. pydhcp-0.2.1rc1/tests/integration/test_dora.py +290 -0
  42. pydhcp-0.2.1rc1/tests/test_async.py +69 -0
  43. pydhcp-0.2.1rc1/tests/test_async_concurrency.py +127 -0
  44. pydhcp-0.2.1rc1/tests/test_basic.py +40 -0
  45. pydhcp-0.2.1rc1/tests/test_cli.py +83 -0
  46. pydhcp-0.2.1rc1/tests/test_lease_backend.py +93 -0
  47. pydhcp-0.2.1rc1/tests/test_malformed_packets.py +72 -0
  48. pydhcp-0.2.1rc1/tests/test_message.py +77 -0
  49. pydhcp-0.2.1rc1/tests/test_option_types.py +374 -0
  50. pydhcp-0.2.1rc1/tests/test_options.py +369 -0
  51. pydhcp-0.2.1rc1/tests/test_permissions.py +32 -0
  52. pydhcp-0.2.1rc1/tests/test_platform_interfaces.py +29 -0
  53. pydhcp-0.2.1rc1/tests/test_rfc_compliance.py +113 -0
@@ -0,0 +1,20 @@
1
+ # Build/dist output and generated docs site
2
+ dist/
3
+ build/
4
+ site/
5
+
6
+ # Agent/harness tooling
7
+ AGENTS.md
8
+ .agents/
9
+ CLAUDE.md
10
+ CLAUDE.local.md
11
+ .claude/
12
+
13
+ # Python-specific patterns
14
+ __pycache__/
15
+ *.py[cod]
16
+ .pytest_cache/
17
+ .mypy_cache/
18
+ .ruff_cache/
19
+ *.egg-info/
20
+ .venv/
@@ -0,0 +1,71 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.1-rc.1] - 2026-07-12
11
+
12
+ ### Added
13
+ - Expanded DHCP option-type registrations so common well-defined options decode to typed values.
14
+ - Added a "Common DHCP Options" docs page with typed examples and updated the custom-options example to prefer typed assignment.
15
+ - Added stricter option-type validation and `ClasslessRoute` truncation checks.
16
+ - Added wildcard listener `per_interface` support and exported `PktInfoUdpTransport`.
17
+ - Added typed codecs and registrations for policy filters, static routes, user classes, encapsulated vendor/relay sub-options, name service search, subnet selection, and RDNSS selection.
18
+
19
+ ### Fixed
20
+ - Made `DhcpMessage.encode()` idempotent and tolerant of reserved flag bits during decode.
21
+ - Corrected `DhcpMessage.dumps()` field labels and `secs` packing behavior.
22
+
23
+ ## [0.2.0] - 2026-07-12
24
+
25
+ ### Added
26
+ - Created `benchmarks/bench_parse.py` packet parsing and serialization performance benchmarks.
27
+ - Added `benchmarks/README.md` documenting performance baselines.
28
+ - Added `AsyncDhcpListener` and `AsyncDhcpServer` classes implementing asyncio-based event loop integration.
29
+ - Added integration tests for async server in `tests/test_async.py`.
30
+ - Configured MkDocs documentation with Material theme and `mkdocstrings` auto-generated API references.
31
+ - Added `Transport`, `UdpTransport`, and `RequestContext` classes for structured transport-layer abstraction and Interface tracking.
32
+ - Added comprehensive unit testing coverage for packet deserialization and type-safe dictionary operations in `test_message.py` and `test_options.py`.
33
+ - Added integration tests verifying standard client DORA sequences and RFC 2131 routing logic in `tests/integration/test_dora.py`.
34
+ - Added missing `ALL_VPNS` option (Tag 254) to `DhcpOptionCode` after comparing against the latest IANA registry.
35
+ - Populated default `ROUTER` and `DNS` lease options in `DhcpServer.acquire_lease` using the server's interface IP.
36
+ - Added pluggable lease backend API (`LeaseBackend`) and implementations (`InMemoryLeaseBackend`, `FileLeaseBackend`) for state preservation and persistence.
37
+ - Added unit and integration tests for lease backends in `tests/test_lease_backend.py` and `tests/integration/test_dora.py`.
38
+ - Added validation checks for hardware address length (hlen <= 16) during packet decoding.
39
+ - Added socket binding error diagnostics that offer actionable suggestions for permission and address-in-use errors.
40
+ - Added unit tests for binding error handling and malformed packet input in `tests/test_permissions.py` and `tests/test_malformed_packets.py`.
41
+ - Added command-line interface (CLI) with `interfaces`, `server`, `packet`, and `bench` subcommands.
42
+ - Added JSON-based configuration loading support in `config.py`.
43
+ - Added in-process metrics counters (`packets_received`, `packets_sent`, etc.) in `metrics.py` to support observability.
44
+ - Added option parsing and lease allocation performance benchmarks in `benchmarks/bench_options.py`.
45
+ - Added async DHCP server concurrency stress tests under `tests/test_async_concurrency.py`.
46
+
47
+ ### Changed
48
+ - Configured strict typechecking configuration in `pyproject.toml` and resolved all mypy type-checking errors across the library.
49
+ - Refactored `DhcpMessageType` and `OptionOverload` to implement the `DhcpOptionType` interface directly and avoid PEP 561 / type conflicts with `BaseFixedLengthInteger` and Enums.
50
+ - Refactored `DhcpServer.handle` to accept `RequestContext` instead of `SocketSession`, split processing into message-type specific handlers (`handle_discover`, etc.), and comply strictly with RFC 2131 routing paths.
51
+ - Enriched `NetworkInterface` and `host_ip_interfaces()` to yield fully detailed adapter metadata.
52
+ - Refactored `DhcpServer` and `AsyncDhcpServer` to accept and delegate lease lifecycle events (allocate, lookup, renew, release) to a configurable `lease_backend`.
53
+ - Refactored options parsing in `DhcpOptions.decode` to handle truncated option lengths gracefully by logging a warning and parsing remaining bytes instead of crashing.
54
+ - Added debug-level logging for packet arrival and lease allocation including client XIDs.
55
+ - Renamed misspelled `contants.py` to `constants.py` and updated all internal references.
56
+ - Added strict `__all__` public exports list to `src/pydhcp/__init__.py`.
57
+
58
+ ### Fixed
59
+ - Fixed bug in `ClasslessRoute` destination descriptor parsing/serialization that caused incorrect length calculations for CIDR/8.
60
+ - Fixed forward reference type resolution issue for `DhcpOption` in `_options.py`.
61
+ - Fixed options encoding `OverflowError` when option size limit is infinite.
62
+ - Fixed `BaseDhcpOptionCode.__int__` returning constant zero, correcting enum integer conversion for option codes.
63
+
64
+ ## [0.1.0] - 2026-07-11
65
+
66
+ ### Added
67
+
68
+ - Initial release.
69
+
70
+ [0.2.0]: https://github.com/jose-pr/pydhcp/compare/v0.1.0...v0.2.0
71
+ [0.1.0]: https://github.com/jose-pr/pydhcp/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jose-pr
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.4
2
+ Name: pydhcp
3
+ Version: 0.2.1rc1
4
+ Summary: A Python DHCP library and server implementation
5
+ Project-URL: Homepage, https://github.com/jose-pr/pydhcp/
6
+ Project-URL: Documentation, https://jose-pr.github.io/pydhcp/
7
+ Project-URL: Issues, https://github.com/jose-pr/pydhcp/issues
8
+ Author: jose-pr
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.9
21
+ Provides-Extra: dev
22
+ Requires-Dist: build; extra == 'dev'
23
+ Requires-Dist: hatchling; extra == 'dev'
24
+ Requires-Dist: mypy; extra == 'dev'
25
+ Requires-Dist: pip-audit; extra == 'dev'
26
+ Requires-Dist: pytest; extra == 'dev'
27
+ Requires-Dist: pytest-cov; extra == 'dev'
28
+ Requires-Dist: twine; extra == 'dev'
29
+ Provides-Extra: docs
30
+ Requires-Dist: mkdocs; extra == 'docs'
31
+ Requires-Dist: mkdocs-material; extra == 'docs'
32
+ Requires-Dist: mkdocstrings[python]; extra == 'docs'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # pydhcp
36
+
37
+ [![Version](https://img.shields.io/pypi/v/pydhcp.svg)](https://pypi.org/project/pydhcp/)
38
+ [![Python versions](https://img.shields.io/pypi/pyversions/pydhcp.svg)](https://pypi.org/project/pydhcp/)
39
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
40
+ [![Docs](https://img.shields.io/badge/docs-latest-blue.svg)](https://jose-pr.github.io/pydhcp/)
41
+
42
+ A Python DHCP library and server implementation.
43
+
44
+ ## Features
45
+
46
+ - **DHCP Packet Parsing** — Full support for parsing and constructing DHCP packets.
47
+ - **DHCP Server** — Highly customizable and async-friendly DHCP server.
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ pip install pydhcp
53
+ ```
54
+
55
+ ## Quick start
56
+
57
+ ### Synchronous Server
58
+ ```python
59
+ from pydhcp.server import DhcpServer
60
+
61
+ server = DhcpServer()
62
+ server.listen()
63
+ ```
64
+
65
+ ### Asynchronous Server
66
+ ```python
67
+ import asyncio
68
+ from pydhcp.server import AsyncDhcpServer
69
+
70
+ async def main():
71
+ server = AsyncDhcpServer()
72
+ await server.start()
73
+ # Keep running or handle other async tasks
74
+ # To stop: await server.stop()
75
+
76
+ asyncio.run(main())
77
+ ```
78
+
79
+ ## Command Line Interface (CLI)
80
+
81
+ `pydhcp` includes a command line interface for listing network adapters, decoding packets, running benchmarks, and starting servers.
82
+
83
+ ```bash
84
+ # List all network interfaces
85
+ pydhcp interfaces
86
+
87
+ # Decode a hex-encoded DHCP packet
88
+ pydhcp packet --decode "01010600..."
89
+
90
+ # Run performance benchmarks
91
+ pydhcp bench
92
+
93
+ # Start the DHCP server from JSON or INI config
94
+ pydhcp server --config config.json
95
+
96
+ # Increase logging while debugging
97
+ pydhcp server --listen 127.0.0.1:6767 --log-level debug
98
+ ```
99
+
100
+ ## Development
101
+
102
+ See development notes for environment setup, dependency install, and test commands.
103
+
104
+ ### Releasing
105
+
106
+ This project follows [Semantic Versioning](https://semver.org/) and keeps a
107
+ [`CHANGELOG.md`](CHANGELOG.md). Pushing a tag matching `v*` triggers the release
108
+ workflow.
109
+
110
+ ### Documentation site
111
+
112
+ MkDocs builds the API reference from `docs/`, published on every release. The docs also include a "Common DHCP Options" page with typed examples.
113
+
114
+ ## License
115
+
116
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,82 @@
1
+ # pydhcp
2
+
3
+ [![Version](https://img.shields.io/pypi/v/pydhcp.svg)](https://pypi.org/project/pydhcp/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/pydhcp.svg)](https://pypi.org/project/pydhcp/)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+ [![Docs](https://img.shields.io/badge/docs-latest-blue.svg)](https://jose-pr.github.io/pydhcp/)
7
+
8
+ A Python DHCP library and server implementation.
9
+
10
+ ## Features
11
+
12
+ - **DHCP Packet Parsing** — Full support for parsing and constructing DHCP packets.
13
+ - **DHCP Server** — Highly customizable and async-friendly DHCP server.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pip install pydhcp
19
+ ```
20
+
21
+ ## Quick start
22
+
23
+ ### Synchronous Server
24
+ ```python
25
+ from pydhcp.server import DhcpServer
26
+
27
+ server = DhcpServer()
28
+ server.listen()
29
+ ```
30
+
31
+ ### Asynchronous Server
32
+ ```python
33
+ import asyncio
34
+ from pydhcp.server import AsyncDhcpServer
35
+
36
+ async def main():
37
+ server = AsyncDhcpServer()
38
+ await server.start()
39
+ # Keep running or handle other async tasks
40
+ # To stop: await server.stop()
41
+
42
+ asyncio.run(main())
43
+ ```
44
+
45
+ ## Command Line Interface (CLI)
46
+
47
+ `pydhcp` includes a command line interface for listing network adapters, decoding packets, running benchmarks, and starting servers.
48
+
49
+ ```bash
50
+ # List all network interfaces
51
+ pydhcp interfaces
52
+
53
+ # Decode a hex-encoded DHCP packet
54
+ pydhcp packet --decode "01010600..."
55
+
56
+ # Run performance benchmarks
57
+ pydhcp bench
58
+
59
+ # Start the DHCP server from JSON or INI config
60
+ pydhcp server --config config.json
61
+
62
+ # Increase logging while debugging
63
+ pydhcp server --listen 127.0.0.1:6767 --log-level debug
64
+ ```
65
+
66
+ ## Development
67
+
68
+ See development notes for environment setup, dependency install, and test commands.
69
+
70
+ ### Releasing
71
+
72
+ This project follows [Semantic Versioning](https://semver.org/) and keeps a
73
+ [`CHANGELOG.md`](CHANGELOG.md). Pushing a tag matching `v*` triggers the release
74
+ workflow.
75
+
76
+ ### Documentation site
77
+
78
+ MkDocs builds the API reference from `docs/`, published on every release. The docs also include a "Common DHCP Options" page with typed examples.
79
+
80
+ ## License
81
+
82
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,25 @@
1
+ # DHCP Library Performance Benchmarks
2
+
3
+ This directory contains the benchmarks for measuring the serialization and deserialization performance of the `pydhcp` library.
4
+
5
+ ## Benchmarks
6
+
7
+ ### 1. Packet Parsing & Serialization (`benchmarks/bench_parse.py`)
8
+ Measures the operations per second (ops/sec) and total duration for 10,000 iterations of:
9
+ - **Decode**: Deserializing a typical `DHCPDISCOVER` packet payload into a `DhcpMessage` object.
10
+ - **Encode**: Serializing a constructed `DhcpMessage` object back into raw bytes.
11
+
12
+ #### Running the Benchmark
13
+ From the repository root directory, run:
14
+ ```bash
15
+ python benchmarks/bench_parse.py
16
+ ```
17
+
18
+ ## Performance Baseline
19
+
20
+ The baseline measurements taken on a Windows development machine (Python 3.12) are as follows:
21
+
22
+ | Operation | Total Time (10k iterations) | Throughput (ops/sec) |
23
+ |---|---|---|
24
+ | **Decode** (Deserialization) | ~0.11s | ~92,600 ops/sec |
25
+ | **Encode** (Serialization) | ~0.08s | ~120,800 ops/sec |
@@ -0,0 +1,58 @@
1
+ import timeit
2
+ import sys
3
+ import pathlib
4
+
5
+ # Ensure src/ is in the import path
6
+ SRC_DIR = pathlib.Path(__file__).parent.parent / "src"
7
+ sys.path.insert(0, SRC_DIR.as_posix())
8
+
9
+ from pydhcp.options import DhcpOptions
10
+ from pydhcp.enum import DhcpOptionCode
11
+ from pydhcp.netutils import IPv4
12
+ from pydhcp.lease import InMemoryLeaseBackend
13
+
14
+ def build_options_payload(option_count: int) -> bytearray:
15
+ opts = DhcpOptions()
16
+ for i in range(1, option_count + 1):
17
+ opts[i] = bytearray([192, 168, 1, i])
18
+ return opts.encode()
19
+
20
+ def test_memory_usage():
21
+ backend = InMemoryLeaseBackend()
22
+ options = DhcpOptions()
23
+ for i in range(1000):
24
+ client_id = f"client-{i}"
25
+ ip = IPv4("192.168.1.1")
26
+ backend.allocate(client_id, ip, 3600, options)
27
+
28
+ def run_benchmarks(iterations: int = 10000):
29
+ print(f"--- Running DHCP Options & Memory Benchmarks ({iterations:,} iterations) ---")
30
+
31
+ p0 = memoryview(build_options_payload(0))
32
+ p5 = memoryview(build_options_payload(5))
33
+ p20 = memoryview(build_options_payload(20))
34
+
35
+ t0 = timeit.timeit(lambda: DhcpOptions().decode(p0), number=iterations)
36
+ t5 = timeit.timeit(lambda: DhcpOptions().decode(p5), number=iterations)
37
+ t20 = timeit.timeit(lambda: DhcpOptions().decode(p20), number=iterations)
38
+
39
+ print(f"Decode with 0 options: {t0:.4f}s ({iterations/t0:.1f} ops/sec)")
40
+ print(f"Decode with 5 options: {t5:.4f}s ({iterations/t5:.1f} ops/sec)")
41
+ print(f"Decode with 20 options: {t20:.4f}s ({iterations/t20:.1f} ops/sec)")
42
+
43
+ opts = DhcpOptions()
44
+ opts[DhcpOptionCode.SUBNET_MASK] = IPv4("255.255.255.0")
45
+
46
+ def round_trip():
47
+ encoded = opts.encode()
48
+ decoded = DhcpOptions()
49
+ decoded.decode(memoryview(encoded))
50
+
51
+ trt = timeit.timeit(round_trip, number=iterations)
52
+ print(f"Round-trip encode/decode: {trt:.4f}s ({iterations/trt:.1f} ops/sec)")
53
+
54
+ t_mem = timeit.timeit(test_memory_usage, number=100)
55
+ print(f"1000 lease allocations (x100 reps): {t_mem:.4f}s ({100/t_mem:.1f} reps/sec)")
56
+
57
+ if __name__ == "__main__":
58
+ run_benchmarks()
@@ -0,0 +1,77 @@
1
+ import timeit
2
+ import sys
3
+ import pathlib
4
+ from datetime import timedelta
5
+
6
+ # Ensure src/ is in the import path
7
+ SRC_DIR = pathlib.Path(__file__).parent.parent / "src"
8
+ sys.path.insert(0, SRC_DIR.as_posix())
9
+
10
+ from pydhcp.message import DhcpMessage
11
+ from pydhcp.enum import OpCode, HardwareAddressType, Flags, DhcpOptionCode, DhcpMessageType
12
+ from pydhcp.netutils import IPv4
13
+ from pydhcp.options import DhcpOptions
14
+
15
+ def build_benchmark_payload() -> bytes:
16
+ options = DhcpOptions()
17
+ options[DhcpOptionCode.DHCP_MESSAGE_TYPE] = bytearray([DhcpMessageType.DHCPDISCOVER.value])
18
+ options[DhcpOptionCode.CLIENT_IDENTIFIER] = bytearray([1, 0, 17, 34, 51, 68, 85])
19
+ options[DhcpOptionCode.PARAMETER_REQUEST_LIST] = bytearray([1, 3, 6, 15, 31, 33, 43, 44, 46, 47, 119, 121, 249, 252])
20
+
21
+ msg = DhcpMessage(
22
+ op=OpCode.BOOTREQUEST,
23
+ htype=HardwareAddressType.ETHERNET,
24
+ hlen=6,
25
+ hops=0,
26
+ xid=0x3903F326,
27
+ secs=timedelta(seconds=0),
28
+ flags=Flags.UNICAST,
29
+ ciaddr=IPv4('0.0.0.0'),
30
+ yiaddr=IPv4('0.0.0.0'),
31
+ siaddr=IPv4('0.0.0.0'),
32
+ giaddr=IPv4('0.0.0.0'),
33
+ chaddr=b'\x00\x11\x22\x33\x44\x55',
34
+ sname='',
35
+ file='',
36
+ options=options
37
+ )
38
+ return bytes(msg.encode())
39
+
40
+ PAYLOAD_BYTES = build_benchmark_payload()
41
+
42
+ def run_benchmarks(iterations: int = 10000) -> dict[str, float]:
43
+ print(f"--- Running DHCP Packet Parsing Benchmarks ({iterations:,} iterations) ---")
44
+
45
+ # 1. Decode Benchmark
46
+ # We use memoryview(PAYLOAD_BYTES) as is typically done in the listener
47
+ payload_mv = memoryview(PAYLOAD_BYTES)
48
+
49
+ def test_decode() -> None:
50
+ DhcpMessage.decode(payload_mv)
51
+
52
+ decode_time = timeit.timeit(test_decode, number=iterations)
53
+ decode_ops_per_sec = iterations / decode_time
54
+ print(f"Decode: {decode_time:.4f} seconds ({decode_ops_per_sec:.1f} ops/sec)")
55
+
56
+ # 2. Encode Benchmark
57
+ msg = DhcpMessage.decode(payload_mv)
58
+
59
+ def test_encode() -> None:
60
+ msg.encode()
61
+
62
+ encode_time = timeit.timeit(test_encode, number=iterations)
63
+ encode_ops_per_sec = iterations / encode_time
64
+ print(f"Encode: {encode_time:.4f} seconds ({encode_ops_per_sec:.1f} ops/sec)")
65
+
66
+ # Return stats for documentation
67
+ return {
68
+ "iterations": iterations,
69
+ "decode_time": decode_time,
70
+ "decode_ops": decode_ops_per_sec,
71
+ "encode_time": encode_time,
72
+ "encode_ops": encode_ops_per_sec,
73
+ }
74
+
75
+
76
+ if __name__ == "__main__":
77
+ run_benchmarks()
@@ -0,0 +1,23 @@
1
+ # API Reference
2
+
3
+ This section provides references for the primary classes in the `pydhcp` package.
4
+
5
+ ## DhcpMessage
6
+
7
+ ::: pydhcp.message.DhcpMessage
8
+
9
+ ## DhcpServer
10
+
11
+ ::: pydhcp.server.DhcpServer
12
+
13
+ ## AsyncDhcpServer
14
+
15
+ ::: pydhcp.server.AsyncDhcpServer
16
+
17
+ ## DhcpListener
18
+
19
+ ::: pydhcp.listener.DhcpListener
20
+
21
+ ## AsyncDhcpListener
22
+
23
+ ::: pydhcp.listener.AsyncDhcpListener
@@ -0,0 +1,45 @@
1
+ # Deployment
2
+
3
+ `pydhcp` is a pure-Python library, so deployment is mostly about running it with the right permissions and network layout.
4
+
5
+ ## Production checklist
6
+
7
+ 1. Run the server under a dedicated service account.
8
+ 2. Make sure the host can bind the DHCP ports you expect to use.
9
+ 3. Confirm the selected interface has the address range you want to serve.
10
+ 4. Keep lease persistence enabled if you need stable client assignment across restarts.
11
+
12
+ ## systemd
13
+
14
+ For Linux services, run the server from a unit that starts the CLI entry point directly.
15
+
16
+ ```ini
17
+ [Unit]
18
+ Description=pydhcp server
19
+ After=network-online.target
20
+
21
+ [Service]
22
+ ExecStart=/opt/pydhcp/.venv/bin/pydhcp server --help
23
+ Restart=on-failure
24
+ User=pydhcp
25
+ Group=pydhcp
26
+
27
+ [Install]
28
+ WantedBy=multi-user.target
29
+ ```
30
+
31
+ Replace `--help` with the server arguments you actually want in production. The CLI accepts JSON or INI configuration files through `--config`.
32
+
33
+ ## Docker
34
+
35
+ The server can also run inside a container if the container is allowed to bind the needed UDP ports and see the host network.
36
+
37
+ - Prefer host networking for real DHCP service.
38
+ - Mount configuration and lease storage explicitly.
39
+ - Keep logs on stdout/stderr so orchestrators can collect them.
40
+
41
+ ## Operational notes
42
+
43
+ - Use the CLI `interfaces` command to confirm interface detection before serving traffic.
44
+ - If you are debugging packet flow, turn on debug logging and look for the transaction ID in the output.
45
+ - Keep an eye on lease backend state after restarts if you are not using the in-memory backend.
@@ -0,0 +1,50 @@
1
+ # Examples
2
+
3
+ This page collects a few short patterns that are useful when you start wiring `pydhcp` into a real service.
4
+
5
+ ## Custom lease backend
6
+
7
+ The server accepts a pluggable lease backend. That makes it easy to persist leases in memory for tests and swap in a file-backed store for simple deployments.
8
+
9
+ ```python
10
+ from pydhcp.lease import InMemoryLeaseBackend
11
+ from pydhcp.server import DhcpServer
12
+
13
+ server = DhcpServer(lease_backend=InMemoryLeaseBackend())
14
+ server.listen()
15
+ ```
16
+
17
+ ## Listening on all interfaces
18
+
19
+ If you want the server to bind every local IPv4 interface, pass `'*'` or `0.0.0.0`.
20
+ You can also force the portable per-interface path with `per_interface=True`.
21
+
22
+ ```python
23
+ from pydhcp.server import DhcpServer
24
+
25
+ server = DhcpServer(listen="*", per_interface=True)
26
+ server.listen()
27
+ ```
28
+
29
+ ## Custom options
30
+
31
+ `DhcpOptions` behaves like an ordered mapping, so you can build option sets explicitly and preserve encode order.
32
+
33
+ ```python
34
+ from pydhcp import DhcpOptions
35
+ from pydhcp.enum import DhcpOptionCode
36
+
37
+ options = DhcpOptions()
38
+ options[DhcpOptionCode.HOSTNAME] = "workstation-01"
39
+ options[DhcpOptionCode.DOMAIN_NAME] = "example.internal"
40
+ ```
41
+
42
+ For more typed examples across the built-in option families, see [Common DHCP Options](options.md).
43
+
44
+ ## Inspecting packets
45
+
46
+ The CLI can decode packets and print their fields, which is handy when you are debugging client behavior or validating captures.
47
+
48
+ ```bash
49
+ pydhcp packet --help
50
+ ```
@@ -0,0 +1,13 @@
1
+ # FAQ
2
+
3
+ ## Why does the server use a synthetic interface on loopback?
4
+
5
+ In sandboxed or minimal environments, interface enumeration may not return a matching `NetworkInterface` record for `127.0.0.1`. The server falls back to a synthetic interface so tests and local demos still work.
6
+
7
+ ## Why are some clients sent broadcast replies?
8
+
9
+ If the server cannot send a direct unicast packet to the requested address, it falls back to broadcast delivery. That keeps local development usable even when the requested lease address is not reachable from the host network.
10
+
11
+ ## Why are the docs split into several short pages?
12
+
13
+ The project has a few different operational concerns now: API reference, examples, deployment, and troubleshooting. Keeping them separate makes it easier to find the right piece without scrolling through a giant wall of text.
@@ -0,0 +1,44 @@
1
+ # pydhcp
2
+
3
+ A Python DHCP library and server implementation.
4
+
5
+ ## Features
6
+
7
+ - **DHCP Packet Parsing & Construction**: Full control and type safety over DHCP message structures.
8
+ - **Synchronous & Asynchronous Sockets**: Standard threaded listening loops (`DhcpListener`/`DhcpServer`) and modern asyncio endpoints (`AsyncDhcpListener`/`AsyncDhcpServer`).
9
+ - **Flexible Options System**: Easy options manipulation using type-safe custom dictionaries.
10
+
11
+ ## Installation
12
+
13
+ Install using pip:
14
+
15
+ ```bash
16
+ pip install pydhcp
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ### Synchronous DHCP Server
22
+ ```python
23
+ from pydhcp.server import DhcpServer
24
+
25
+ # Automatically binds to default DHCP server ports
26
+ server = DhcpServer()
27
+ server.listen()
28
+ ```
29
+
30
+ ### Asynchronous DHCP Server
31
+ ```python
32
+ import asyncio
33
+ from pydhcp.server import AsyncDhcpServer
34
+
35
+ async def main():
36
+ server = AsyncDhcpServer()
37
+ await server.start()
38
+
39
+ # Wait or run other async application logic
40
+ # To shut down cleanly:
41
+ # await server.stop()
42
+
43
+ asyncio.run(main())
44
+ ```