std.net.arp
ARP-Client nach RFC 826 — Address Resolution Protocol für IPv4 über Ethernet. Baut ARP-Request- und Reply-Frames, parst empfangene Frames und löst IP-Adressen ohne Raw-Socket über den Kernel-ARP-Cache auf.
import std.net.arp;
import std.alloc;
// MAC-Adresse für 192.168.1.1 aus Kernel-Cache auflesen
var result: int64 := alloc(ARP_RESULT_SIZE);
if (ArpResolve(IPPack(192, 168, 1, 1), result) == 0) {
var macPtr: int64 := result + ARP_RESULT_SENDER_MAC;
// macPtr[0..5] = aufgelöste MAC-Adresse
}
free(result, ARP_RESULT_SIZE);
Berechtigung:ArpResolvebenötigt keinen Raw-Socket und kein root — nur ein UDP-Socket für denSIOCGARP-ioctl.ArpBuildRequest/Replyerzeugen nur den Frame-Puffer; das Senden über einen Raw-Socket erfordertCAP_NET_RAW.
Imports
std.net.socketstd.alloc
Konstanten
Frame-Feldoffsets (ARP_FRAME_SIZE = 42 Bytes)
Ein ARP-Frame besteht aus einem 14-Byte-Ethernet-Header und einem 28-Byte-ARP-Payload. Alle Mehrbytefelder sind Big-Endian (Network Byte Order).
Ethernet-Header (Bytes 0–13):
| Konstante | Offset | Größe | Inhalt |
|---|---|---|---|
ARP_ETH_DST | 0 | 6 | Ziel-MAC-Adresse (bei REQUEST: ff:ff:ff:ff:ff:ff) |
ARP_ETH_SRC | 6 | 6 | Quell-MAC-Adresse |
ARP_ETH_TYPE | 12 | 2 | EtherType = 0x0806 (ARP) |
ARP-Payload (Bytes 14–41):
| Konstante | Offset | Größe | Inhalt |
|---|---|---|---|
ARP_HRD | 14 | 2 | Hardware-Typ (1 = Ethernet) |
ARP_PRO | 16 | 2 | Protokoll-Typ (0x0800 = IPv4) |
ARP_HLEN | 18 | 1 | Hardware-Adresslänge (6) |
ARP_PLEN | 19 | 1 | Protokoll-Adresslänge (4) |
ARP_OP | 20 | 2 | Operationscode (1=REQUEST, 2=REPLY) |
ARP_SHA | 22 | 6 | Sender Hardware Address (MAC) |
ARP_SIP | 28 | 4 | Sender IP-Adresse |
ARP_THA | 32 | 6 | Target Hardware Address (bei REQUEST: 00:00:00:00:00:00) |
ARP_TIP | 38 | 4 | Target IP-Adresse |
Operationscodes
| Konstante | Wert | Bedeutung |
|---|---|---|
ARP_OP_REQUEST | 1 | Wer hat IP X? — Broadcast |
ARP_OP_REPLY | 2 | IP X hat MAC Y — Unicast |
ARP_OP_RREQUEST | 3 | Reverse ARP Request |
ARP_OP_RREPLY | 4 | Reverse ARP Reply |
Wire-Konstanten
| Konstante | Wert | Bedeutung |
|---|---|---|
ARP_HTYPE_ETHER | 1 | Hardware-Typ Ethernet |
ARP_PROTO_IPV4 | 2048 (0x0800) | Protokoll-Typ IPv4 |
ARP_ETYPE_B0 | 8 (0x08) | EtherType High-Byte |
ARP_ETYPE_B1 | 6 (0x06) | EtherType Low-Byte |
Result-Struct (ARP_RESULT_SIZE = 48 Bytes)
Wird vom Caller alloziert. MAC-Adressen werden als 6 aufeinander folgende Bytes ab dem angegebenen Offset gespeichert (mit peek8 byteweise lesen).
| Offset-Konstante | Offset | Inhalt |
|---|---|---|
ARP_RESULT_SENDER_IP | 0 | Sender-IP (IPPack-Format) |
ARP_RESULT_SENDER_MAC | 8 | Sender-MAC (Bytes +8 bis +13) |
ARP_RESULT_TARGET_IP | 16 | Ziel-IP (IPPack-Format) |
ARP_RESULT_TARGET_MAC | 24 | Ziel-MAC (Bytes +24 bis +29) |
ARP_RESULT_OP | 32 | Operationscode (1 oder 2) |
ARP_RESULT_OK | 40 | 1 = gültiges Ergebnis |
Funktionen
Frame-Builder
| Signatur | Beschreibung |
|---|---|
ArpBuildRequest(buf: int64, srcMac: int64, srcIP: int64, dstIP: int64): int64 | Baut ARP-REQUEST-Frame in buf (≥ 42 Bytes). Ethernet-Ziel = Broadcast (ff:ff:ff:ff:ff:ff); ARP-THA = 00:00:00:00:00:00. Gibt ARP_FRAME_SIZE (42) zurück. |
ArpBuildReply(buf: int64, srcMac: int64, srcIP: int64, dstMac: int64, dstIP: int64): int64 | Baut ARP-REPLY-Frame. srcMac/srcIP = antwortender Host; dstMac/dstIP = ursprünglicher Fragesteller. Gibt ARP_FRAME_SIZE (42) zurück. |
Frame-Parser
| Signatur | Beschreibung |
|---|---|
ArpParse(buf: int64, len: int64, result: int64): void | Parst rohen Ethernet-Frame. Setzt ARP_RESULT_OK=1 wenn EtherType=0x0806, hlen=6, plen=4. Füllt alle Felder des Result-Structs. buf muss den vollständigen 42-Byte-Frame enthalten. |
Kernel-Cache-Auflösung
| Signatur | Beschreibung |
|---|---|
ArpResolve(ip: int64, result: int64): int64 | Liest MAC-Adresse für ip aus dem Kernel-ARP-Cache (SIOCGARP-ioctl, kein Raw-Socket, kein root). Setzt ARP_RESULT_OK=1, ARP_RESULT_SENDER_MAC und ARP_RESULT_TARGET_MAC auf die aufgelöste MAC, ARP_RESULT_TARGET_IP auf ip. Gibt 0 bei Erfolg, -1 wenn IP nicht im Cache oder bei Fehler. |
Frame-Layout
Byte: 0 6 12 14 16 18 19 20 22 28 32 38
┌────┬────┬──┬──┬──┬─┬─┬──┬────┬────┬────┬────┐
ETH: │dst │src │08│06│ │ │ │ │ │ │ │ │
ARP: │HRD│PRO│HL│PL│OP│SHA │SIP │THA │TIP │
└────┴────┴──┴──┴──┴─┴─┴──┴────┴────┴────┴────┘
|←── 14B Ethernet ──→|←──────── 28B ARP ───────→|
42
Codebeispiel — ARP-Request senden und antwortenden Frame parsen
import std.net.arp;
import std.net.socket;
import std.net.types;
import std.alloc;
fn resolveViaRaw(srcMac: int64, srcIP: int64, targetIP: int64): int64 {
// Raw-Socket für Ethernet-Layer (erfordert CAP_NET_RAW)
var rawSock: int64 := sys_socket(AF_PACKET, SOCK_RAW, 0x0806);
if (rawSock < 0) { return 0 - 1; }
// ARP-Request bauen und senden
var frame: int64 := alloc(ARP_FRAME_SIZE);
ArpBuildRequest(frame, srcMac, srcIP, targetIP);
// ... frame über rawSock senden ...
// Antwort empfangen und parsen
var reply: int64 := alloc(ARP_FRAME_SIZE);
var result: int64 := alloc(ARP_RESULT_SIZE);
// ... reply über rawSock empfangen ...
ArpParse(reply, ARP_FRAME_SIZE, result);
if (peek64(result + ARP_RESULT_OK) == 1) {
var mac: int64 := result + ARP_RESULT_SENDER_MAC;
// mac[0..5] = aufgelöste MAC
}
free(result, ARP_RESULT_SIZE);
free(reply, ARP_FRAME_SIZE);
free(frame, ARP_FRAME_SIZE);
return 0;
}
fn resolveViaCache(ip: int64) {
// Einfacher Weg: Kernel-Cache abfragen (kein root nötig)
var result: int64 := alloc(ARP_RESULT_SIZE);
if (ArpResolve(ip, result) == 0) {
var base: int64 := result + ARP_RESULT_SENDER_MAC;
Print(peek8(base)); Print(":");
Print(peek8(base + 1)); Print(":");
Print(peek8(base + 2)); Print(":");
Print(peek8(base + 3)); Print(":");
Print(peek8(base + 4)); Print(":");
PrintLn(peek8(base + 5));
}
free(result, ARP_RESULT_SIZE);
}
Hinweise
- ArpResolve ohne root: Nutzt
SIOCGARP(ioctl 0x8954) über einen normalen UDP-Socket. Erzeugt keinen Netzwerkverkehr — liest nur den bestehenden Kernel-Cache. Die IP muss vorher durch Ping, connect() oder ähnliches in den Cache gebracht worden sein. - Raw-Socket für Request:
ArpBuildRequestundArpBuildReplybauen nur den Puffer. Zum tatsächlichen Senden auf Layer 2 wird einAF_PACKET-Raw-Socket benötigt (CAP_NET_RAWoder root). - IP-Format: Alle IP-Felder verwenden das
IPPack-Format ausstd.net.types— Big-Endian uint32 in int64. - MAC-Zugriff: MACs im Result-Struct werden mit
peek8byteweise gelesen (6 Bytes ab dem jeweiligen Offset-Konstante). - ArpResolve result: Setzt
SENDER_MACundTARGET_MACauf dieselbe aufgelöste MAC;TARGET_IPwird auf die angefragte IP gesetzt,SENDER_IPbleibt 0. - RARP:
ARP_OP_RREQUEST/RREPLYsind als Konstanten definiert (3/4);ArpBuildRequest/Replyunterstützen sie nicht direkt — den OP-Code nach dem Build-Call manuell perarpWrite16BE(intern) oderpoke8setzen.
Quelldatei
| Unit | Datei |
|---|---|
std.net.arp | std/net/arp.lyx |
Letzte Aktualisierung: 2026-06-17
