std.net.dhcp
DHCP-Client nach RFC 2131 — vollständige IP-Adressvergabe über UDP-Broadcast. Deckt den gesamten DORA-Prozess ab (Discover → Offer → Request → Acknowledge) und stellt Paket-Builder, Reply-Parser und High-Level-Lease-Funktion bereit.
import std.net.dhcp;
import std.alloc;
// Vollständigen Lease in einem Aufruf holen
var mac: int64 := alloc(6);
var result: int64 := alloc(DHCP_RESULT_SIZE);
// mac mit 6 Byte Ethernet-Adresse befüllen ...
poke8(mac, 0xAA); poke8(mac+1, 0xBB); // ...
if (DhcpLease(mac, result) == 0) {
var ip: int64 := peek64(result + DHCP_RESULT_IP);
var gw: int64 := peek64(result + DHCP_RESULT_GW);
var lease: int64 := peek64(result + DHCP_RESULT_LEASE);
}
free(result, DHCP_RESULT_SIZE);
free(mac, 6);
Berechtigung: Port 68 < 1024 — erfordert root oder CAP_NET_BIND_SERVICE.
Imports
std.net.socket
std.net.syscalls
std.net.types
std.alloc
Konstanten
Ports
| Konstante | Wert | Bedeutung |
DHCP_PORT_SERVER | 67 | UDP-Port des DHCP-Servers |
DHCP_PORT_CLIENT | 68 | UDP-Port des DHCP-Clients |
Operationscodes
| Konstante | Wert | Bedeutung |
DHCP_OP_REQUEST | 1 | BOOTREQUEST — Client→Server |
DHCP_OP_REPLY | 2 | BOOTREPLY — Server→Client |
DHCP-Nachrichtentypen (Option 53)
| Konstante | Wert | Bedeutung |
DHCP_MSG_DISCOVER | 1 | Client sucht DHCP-Server |
DHCP_MSG_OFFER | 2 | Server bietet IP an |
DHCP_MSG_REQUEST | 3 | Client fordert angebotene IP an |
DHCP_MSG_DECLINE | 4 | Client lehnt angebotene IP ab |
DHCP_MSG_ACK | 5 | Server bestätigt Lease |
DHCP_MSG_NAK | 6 | Server verweigert Lease |
DHCP_MSG_RELEASE | 7 | Client gibt IP frei |
DHCP_MSG_INFORM | 8 | Client fragt Konfiguration ohne IP-Zuweisung |
Options-Codes
| Konstante | Wert | Bedeutung |
DHCP_OPT_SUBNET | 1 | Subnet Mask |
DHCP_OPT_ROUTER | 3 | Default Gateway |
DHCP_OPT_DNS | 6 | DNS-Server (erster Eintrag wird gespeichert) |
DHCP_OPT_HOSTNAME | 12 | Hostname (nur deklariert, nicht gesetzt) |
DHCP_OPT_DOMAIN | 15 | Domain Name (nur angefordert, nicht geparst) |
DHCP_OPT_REQIP | 50 | Requested IP Address |
DHCP_OPT_LEASE | 51 | Lease-Zeit in Sekunden |
DHCP_OPT_MSGTYPE | 53 | Nachrichtentyp |
DHCP_OPT_SERVERID | 54 | Server Identifier (IP des DHCP-Servers) |
DHCP_OPT_PARAMREQ | 55 | Parameter Request List |
DHCP_OPT_PAD | 0 | Padding-Byte |
DHCP_OPT_END | 255 | Ende der Options |
Paket-Feldoffsets (RFC 2131 §2)
| Konstante | Offset | Größe | Inhalt |
DHCP_OFFS_OP | 0 | 1 | Operationscode |
DHCP_OFFS_HTYPE | 1 | 1 | Hardware-Typ (1 = Ethernet) |
DHCP_OFFS_HLEN | 2 | 1 | Hardware-Adresslänge (6 für MAC) |
DHCP_OFFS_HOPS | 3 | 1 | Relay-Agent-Hops |
DHCP_OFFS_XID | 4 | 4 | Transaction ID (Big-Endian) |
DHCP_OFFS_SECS | 8 | 2 | Sekunden seit Start |
DHCP_OFFS_FLAGS | 10 | 2 | Flags (Bit 15 = Broadcast) |
DHCP_OFFS_CIADDR | 12 | 4 | Client IP (bei Erneuerung) |
DHCP_OFFS_YIADDR | 16 | 4 | Angebotene/zugewiesene IP |
DHCP_OFFS_SIADDR | 20 | 4 | Nächster Server |
DHCP_OFFS_GIADDR | 24 | 4 | Relay Agent IP |
DHCP_OFFS_CHADDR | 28 | 16 | Client-Hardware-Adresse (MAC in Byte 0–5) |
DHCP_OFFS_SNAME | 44 | 64 | Server-Hostname |
DHCP_OFFS_FILE | 108 | 128 | Boot-Dateiname |
DHCP_OFFS_COOKIE | 236 | 4 | Magic Cookie (0x63825363) |
DHCP_OFFS_OPTIONS | 240 | — | Beginn der Options |
DHCP_MIN_LEN | — | 300 | Mindestgröße (BOOTP-kompatibel) |
Sonstiges
| Konstante | Wert | Bedeutung |
DHCP_FLAG_BROADCAST | 128 (0x80) | Broadcast-Bit (Byte 10, Bit 7) |
DHCP_MAGIC_B0..B3 | 99,130,83,99 | Magic Cookie 0x63825363 |
DHCP_HTYPE_ETHER | 1 | Hardware-Typ Ethernet |
Result-Struct (DHCP_RESULT_SIZE = 72 Bytes)
Wird vom Caller alloziert und mit Nullen initialisiert. DhcpParseReply, DhcpDiscover, DhcpRequest und DhcpLease schreiben hinein.
Alle IP-Adressen sind im selben gepackten Format wie IPPack() aus std.net.types gespeichert (Big-Endian uint32 in int64).
| Offset-Konstante | Offset | Inhalt |
DHCP_RESULT_IP | 0 | Zugewiesene IP-Adresse |
DHCP_RESULT_MASK | 8 | Subnetzmaske |
DHCP_RESULT_GW | 16 | Default Gateway |
DHCP_RESULT_DNS | 24 | Primärer DNS-Server (erster aus Option 6) |
DHCP_RESULT_LEASE | 32 | Lease-Zeit in Sekunden |
DHCP_RESULT_SERVER | 40 | DHCP-Server-IP (Option 54) |
DHCP_RESULT_XID | 48 | Transaction ID |
DHCP_RESULT_TYPE | 56 | Nachrichtentyp (2=OFFER, 5=ACK, 6=NAK) |
DHCP_RESULT_OK | 64 | 1 = Lease erfolgreich erhalten |
Funktionen
Paket-Builder
| Signatur | Beschreibung |
DhcpBuildDiscover(buf: int64, mac: int64, xid: int64): int64 | Baut DHCPDISCOVER-Paket in buf (≥ DHCP_MIN_LEN Bytes). mac = Zeiger auf 6-Byte-MAC. Broadcast-Flag gesetzt; Parameter Request List: Subnet, Router, DNS, Domain. Gibt DHCP_MIN_LEN zurück. |
DhcpBuildRequest(buf: int64, mac: int64, xid: int64, offeredIP: int64, serverIP: int64): int64 | Baut DHCPREQUEST-Paket. offeredIP und serverIP aus dem vorherigen OFFER übernommen (Option 50 + 54 werden gesetzt). Gibt DHCP_MIN_LEN zurück. |
Reply-Parser
| Signatur | Beschreibung |
DhcpParseReply(buf: int64, len: int64, result: int64): void | Parst DHCP-Server-Antwort (OFFER oder ACK). Prüft OP=REPLY und Magic Cookie. Setzt DHCP_RESULT_OK=1 bei OFFER oder ACK; 0 bei NAK, ungültigem Paket oder zu kurzem Puffer. Füllt IP, Mask, GW, DNS, Lease, Server, Type. |
High-Level Lease-Funktionen
| Signatur | Beschreibung |
DhcpDiscover(mac: int64, xid: int64, result: int64): int64 | Sendet DHCPDISCOVER (UDP-Broadcast) und wartet bis zu 5 Sekunden auf DHCPOFFER. Gibt 0 zurück wenn OFFER erhalten, -1 bei Fehler oder Timeout. |
DhcpRequest(mac: int64, xid: int64, result: int64): int64 | Sendet DHCPREQUEST (liest offeredIP und serverIP aus result) und wartet bis zu 5 Sekunden auf DHCPACK. Gibt 0 nur zurück wenn DHCP_RESULT_TYPE = DHCP_MSG_ACK. |
DhcpLease(mac: int64, result: int64): int64 | Vollständiger DORA-Prozess in einem Aufruf: Discover → Offer → Request → Acknowledge. XID wird aus den ersten 4 MAC-Bytes abgeleitet. Gibt 0 bei erfolgreichem Lease, -1 bei Fehler zurück. |
DORA-Ablauf
Client Server (255.255.255.255:67)
| |
|── DHCPDISCOVER (Broadcast) ────>| xid = MAC[0..3]
|<─ DHCPOFFER ────────────────────| yiaddr=192.168.1.100, srv=192.168.1.1
| |
|── DHCPREQUEST (Broadcast) ─────>| opt50=192.168.1.100, opt54=192.168.1.1
|<─ DHCPACK ──────────────────────| Lease bestätigt, Lease-Zeit: 43200s
DhcpLease() führt den gesamten Ablauf durch. DhcpDiscover() und DhcpRequest() erlauben manuelle Steuerung (z. B. für Fehlerbehandlung oder Logging zwischen den Schritten).
Codebeispiel — Manueller DORA-Ablauf
import std.net.dhcp;
import std.net.types;
import std.alloc;
fn acquireLease(mac: int64): int64 {
var result: int64 := alloc(DHCP_RESULT_SIZE);
var xid: int64 := peek8(mac);
xid := (xid << 8) | peek8(mac + 1);
xid := (xid << 8) | peek8(mac + 2);
xid := (xid << 8) | peek8(mac + 3);
if (DhcpDiscover(mac, xid, result) < 0) {
free(result, DHCP_RESULT_SIZE);
return 0 - 1;
}
var offeredIP: int64 := peek64(result + DHCP_RESULT_IP);
var srvIP: int64 := peek64(result + DHCP_RESULT_SERVER);
// Hier könnte Validierung des OFFER stattfinden ...
if (DhcpRequest(mac, xid, result) < 0) {
free(result, DHCP_RESULT_SIZE);
return 0 - 1;
}
var ip: int64 := peek64(result + DHCP_RESULT_IP);
var mask: int64 := peek64(result + DHCP_RESULT_MASK);
var gw: int64 := peek64(result + DHCP_RESULT_GW);
var dns: int64 := peek64(result + DHCP_RESULT_DNS);
var lease: int64 := peek64(result + DHCP_RESULT_LEASE);
// IP-Adresse z. B. an Netzwerk-Interface binden ...
// Lease-Erneuerung nach lease/2 Sekunden nötig
free(result, DHCP_RESULT_SIZE);
return 0;
}
Hinweise
Berechtigung: DhcpDiscover und DhcpRequest binden Port 68 — erfordert root oder CAP_NET_BIND_SERVICE. Auf Linux genügt: setcap cap_net_bind_service+ep ./programm.
IP-Format: Alle IP-Adressen im Result-Struct verwenden das IPPack-Format aus std.net.types (Big-Endian uint32 in int64). Zum Anzeigen: IpToStr() verwenden.
Timeout: DhcpDiscover und DhcpRequest warten je maximal 5 Sekunden auf eine Antwort (SocketCanRead(fd, 5000)). Kein automatischer Retry.
Kein Lease-Renewal: Diese Unit macht keine automatische Lease-Erneuerung. Die Anwendung muss nach lease/2 Sekunden DhcpLease erneut aufrufen.
XID: DhcpLease leitet die Transaction ID aus den ersten 4 MAC-Bytes ab. Bei mehreren gleichzeitigen Clients mit ähnlichen MACs kann es zu XID-Kollisionen kommen — in diesem Fall DhcpDiscover/DhcpRequest direkt mit einer zufälligen XID verwenden.
DNS: Nur der erste
DNS-Server (Byte 0–3 von Option 6) wird gespeichert. Mehrere
DNS-Server werden ignoriert.
BOOTP-Kompatibilität: Pakete sind mindestens 300 Bytes lang (DHCP_MIN_LEN) für ältere BOOTP-Server.
Quelldatei
| Unit | Datei |
std.net.dhcp | std/net/dhcp.lyx |
Letzte Aktualisierung: 2026-06-17