Reine Frame-Builder — eth, ipv4, udp, arp/frame, dhcp/frame
Fünf Units, die Netzwerk-Header nur bauen und lesen — ohne Sockets, ohne Syscalls, ohne Speicheranforderung. Jede Funktion schreibt in einen Puffer, den der Aufrufer stellt.
Genau das macht sie kernel-tauglich: Sie haben keine Importe und keine Laufzeitabhängigkeit und lassen sich deshalb im Kernel von LyxOS ebenso verwenden wie in einem gewöhnlichen Linux-Programm.
std.net.arp.frame und std.net.dhcp.frame sind eigenständige Kopien, keine Basis der POSIX-Units. std.net.arp und
std.net.dhcp enthalten dieselben Bau- und Lesefunktionen unter denselben Namen noch einmal und ergänzen das, was Syscalls braucht (ioctl-Abfrage der ARP-Tabelle, UDP-Socket für die Lease).
Beide zusammen zu importieren gibt eine Namenskollision — man entscheidet sich für eine Seite: die reine Fassung, wenn man die Bytes selbst verschickt oder im Kernel arbeitet, die POSIX-Fassung, wenn man
ArpResolve oder
DhcpLease braucht.
| Unit | Aufgabe |
std.net.eth | Ethernet-II-Rahmen (14 Byte) |
std.net.ipv4 | IPv4-Header (20 Byte) samt Prüfsumme |
std.net.udp | UDP-Header (8 Byte) |
std.net.arp.frame | ARP-Rahmen bauen und auswerten (RFC 826) |
std.net.dhcp.frame | DHCP-Pakete bauen und auswerten (RFC 2131) |
→ std.net · std.net.arp · std.net.dhcp · Standard Library
std.net.eth — Ethernet II
| Konstante | Wert |
ETH_HDR_SIZE | 14 |
ETH_P_IP | 0x0800 (2048) |
ETH_P_ARP | 0x0806 (2054) |
ETH_P_IPV6 | 0x86DD (34525) |
| Signatur | Beschreibung |
EthBuildFrame(buf, dst_mac, src_mac, ethertype): int64 | Schreibt den 14-Byte-Header; liefert 14. dst_mac/src_mac zeigen auf je 6 Byte |
EthBroadcastMac(buf) | Füllt 6 Byte mit ff:ff:ff:ff:ff:ff |
EthZeroMac(buf) | Füllt 6 Byte mit Nullen |
EthCopyMac(dst, src) | Kopiert 6 Byte |
EthReadType(buf): int64 | Liest den EtherType (Offset 12, Big Endian) aus einem empfangenen Rahmen |
Belegung: Bytes 0–5 Ziel-MAC, 6–11 Quell-MAC, 12–13 EtherType (Big Endian).
| Konstante | Wert |
IPV4_HDR_SIZE | 20 |
IP_PROTO_ICMP / TCP / UDP / RAW | 1 / 6 / 17 / 255 |
| Signatur | Beschreibung |
IpAddr(a, b, c, d): int64 | Vier Oktette zu einer gepackten Adresse |
IpBroadcast(): int64 | 0xFFFFFFFF |
IpChecksum(hdr): int64 | 16-Bit-Einerkomplement-Prüfsumme über den Header |
IpBuildHeader(buf, src, dst, proto, payload_len): int64 | Schreibt den 20-Byte-Header samt Prüfsumme; liefert 20 |
| Konstante | Wert |
UDP_HDR_SIZE | 8 |
UDP_PORT_DHCP_SERVER / CLIENT | 67 / 68 |
UDP_PORT_DNS / UDP_PORT_NTP | 53 / 123 |
| Signatur | Beschreibung |
UdpBuildHeader(buf, src_port, dst_port, payload_len): int64 | Schreibt den 8-Byte-Header; liefert 8. Ports in Wirtsbyte-Reihenfolge |
UdpReadSrcPort(buf) / UdpReadDstPort(buf) / UdpReadLength(buf) | Felder eines empfangenen Segments lesen |
Die UDP-Prüfsumme wird auf 0 gesetzt, also abgeschaltet. Über IPv4 ist das nach
RFC 768 zulässig, über IPv6 dagegen
nicht — dort ist die Prüfsumme Pflicht. Diese Unit taugt damit nur für IPv4.
std.net.arp.frame — ARP bauen und auswerten
Der reine Teil von std.net.arp: Rahmen bauen und einlesen. Wer die ARP-Tabelle des Kernels abfragen will (SIOCGARP-ioctl), nimmt std.net.arp.
| Signatur | Beschreibung |
ArpBuildRequest(buf, srcMac, srcIP, dstIP): int64 | 42-Byte-Rahmen: „Wem gehört dstIP?„ — Eth-Ziel Broadcast, Ziel-MAC im ARP-Teil auf 00:00 |
ArpBuildReply(buf, srcMac, srcIP, dstMac, dstIP): int64 | 42-Byte-Antwortrahmen |
ArpParse(buf, len, result): int64 | Prüft EtherType, hlen und plen und schreibt das Ergebnis in einen ARP_RESULT_SIZE-Puffer |
| Konstantengruppe | Inhalt |
| Frame-Offsets | ARP_ETH_DST 0, ARP_ETH_SRC 6, ARP_ETH_TYPE 12, ARP_HRD 14, ARP_PRO 16, ARP_HLEN 18, ARP_PLEN 19, ARP_OP 20, ARP_SHA 22, ARP_SIP 28, ARP_THA 32, ARP_TIP 38; ARP_FRAME_SIZE 42 |
| Op-Codes | ARP_OP_REQUEST 1, ARP_OP_REPLY 2, ARP_OP_RREQUEST 3, ARP_OP_RREPLY 4 |
| Typen | ARP_HTYPE_ETHER 1, ARP_PROTO_IPV4 0x0800 |
| Ergebnis-Offsets | ARP_RESULT_SENDER_IP 0, SENDER_MAC 8, TARGET_IP 16, TARGET_MAC 24, OP 32, OK 40; ARP_RESULT_SIZE 48 |
std.net.dhcp.frame — DHCP bauen und auswerten
Der reine Teil von std.net.dhcp. Für die vollständige DORA-Sequenz über einen UDP-Socket std.net.dhcp verwenden.
| Signatur | Beschreibung |
DhcpBuildDiscover(buf, mac, xid): int64 | DISCOVER-Paket; liefert DHCP_MIN_LEN |
DhcpBuildRequest(buf, mac, xid, offIP, srvIP): int64 | REQUEST-Paket auf ein Angebot |
DhcpParseReply(buf, len, result): int64 | OFFER/ACK auswerten; NAK setzt das OK-Feld auf 0 |
| Konstantengruppe | Inhalt |
| Ports | DHCP_PORT_SERVER 67, DHCP_PORT_CLIENT 68 |
| Nachrichtentypen | DHCP_MSG_DISCOVER 1 … DHCP_MSG_INFORM 8 (OFFER 2, REQUEST 3, ACK 5, NAK 6) |
| Optionen | DHCP_OPT_SUBNET 1, ROUTER 3, DNS 6, HOSTNAME 12, DOMAIN 15, REQIP 50, LEASE 51, MSGTYPE 53, SERVERID 54, PARAMREQ 55, PAD 0, END 255 |
| Feld-Offsets | DHCP_OFFS_OP 0, HTYPE 1, HLEN 2, HOPS 3, XID 4, … |
Ein Paket von Hand zusammensetzen
Die drei Kopf-Units stapeln sich in der Reihenfolge, in der die Bytes auf der Leitung stehen — Ethernet, dann IPv4, dann UDP:
import std.net.eth;
import std.net.ipv4;
import std.net.udp;
fn BaueUdpPaket(buf: int64, srcMac: int64, dstMac: int64, nutzlast: int64): int64 {
var pos: int64 := EthBuildFrame(buf, dstMac, srcMac, ETH_P_IP);
var src: int64 := IpAddr(192, 168, 1, 10);
var dst: int64 := IpAddr(192, 168, 1, 1);
pos := pos + IpBuildHeader(buf + pos, src, dst, IP_PROTO_UDP, UDP_HDR_SIZE + nutzlast);
pos := pos + UdpBuildHeader(buf + pos, 5000, UDP_PORT_DNS, nutzlast);
return pos; // 14 + 20 + 8 = 42, danach folgt die Nutzlast
}
Die IPv4-Prüfsumme setzt IpBuildHeader selbst — IpChecksum braucht man nur, wenn man einen Header nachträglich verändert.
Letzte Aktualisierung: 2026-08-11