
Wie Envoy xDS, aber für eBPF-Filter
Wie Envoy xDS, aber für eBPF-Filter.
Netfence läuft als Dienstprogramm auf Ihren VM/Container-Hosts und injiziert automatisch eBPF-Filterprogramme in Cgroups und Netzwerkschnittstellen, mit einem integrierten DNS-Server, der erlaubte Domänen auflöst und die IP-Erlaubnisliste befüllt.
Netfence-Daemons können allein über ihre lokale Unix-Socket-API gesteuert werden oder sich mit einer zentralen Steuerungsebene verbinden, die Sie über gRPC implementieren, um Erlaubnislisten/Sperrlisten mit Ihrem Backend zu synchronisieren.
Ihre Steuerungsebene schiebt Netzwerkregeln wie ALLOW *.pypi.org oder ALLOW 10.0.0.0/16 an angehängte Schnittstellen/Cgroups. Wenn eine VM/ein Container DNS abfragt, löst Netfence dies auf, fügt die IPs zum eBPF-Filter hinzu und verwirft den Verkehr zu unbekannten IPs, bevor er den Host verlässt, mit einem Overhead auf dem warmen Pfad, der in aktuellen Benchmarks praktisch nicht von einem normalen Socket-Connect zu unterscheiden ist.
Im Erlaubnislistenmodus ist IPv4-Link-Local (169.254.0.0/16) standardmäßig nicht mehr automatisch erlaubt – der Cloud-Metadatendienst (169.254.169.254) ist also blockiert, sofern nicht explizit erlaubt. Dies ist beabsichtigt: Der Metadatendienst ist ein Ziel für Credential-Diebstahl, und sandboxed Workloads müssen ihn nicht implizit erreichen können. Localhost (127.0.0.0/8, ::1) und IPv6-Nachbarschaftserkennung (fe80::/10, ff02::/16) bleiben standardmäßig erlaubt, damit grundlegende Konnektivität und NDP funktionieren. Um den Metadatendienst für einen Workload zuzulassen, erlauben Sie 169.254.169.254/32 (eine Überschreibung pro Anhang über die Steuerungsebene ist als geplante Erweiterung vorgesehen).
IPv4-Broadcast (255.255.255.255) und Multicast (224.0.0.0/4) haben keine Ausnahme und unterliegen der Richtlinie. Daher wird im TC-Erlaubnislistenmodus Verkehr wie DHCP-Erneuerungs-Broadcasts blockiert, sofern nicht explizit erlaubt. Ausnahme-Prüfungen laufen vor der Sperrliste, daher kann ein ausgenommener Bereich nur blockiert werden, indem seine Ausnahme deaktiviert wird – und da IPv4-Link-Local jetzt standardmäßig deaktiviert ist, kann der Sperrlistenmodus auch den Metadatendienst blockieren.
Einige wesentliche Vorteile dieser Lösung, die andere Optionen normalerweise nicht bieten:
secretdata.someattacker.com gibt)Meines Wissens nach bietet keine andere Lösung alle diese Funktionen zusammen.
Bekannte Einschränkung: Cgroup-Anhänge filtern auf der Socket-Ebene (connect/sendmsg-Hooks), daher kann ein Prozess mit CAP_NET_RAW Rohpakete erstellen, die diese umgehen. Verwenden Sie einen TC-Anhang (Schnittstelle), der auf der Geräteebene filtert, für Workloads, die CAP_NET_RAW halten könnten.
Allerdings hat dies etwas mehr Overhead als so etwas wie httpjail.
Diese Zahlen wurden im privilegierten Docker-Linux-Gate auf linux/arm64 mit make bench-docker gemessen. Die Werte sind Mediane von fünf Stichproben.
Der Warm-Socket-Benchmark verwendet verbundene UDP-Sockets, um die Kosten des EBPF-Hooks cgroup/connect4 von der TCP-Handshake-Latenz zu isolieren. In diesem Pfad hat DNS die Domäne bereits aufgelöst, die IP liegt noch innerhalb der TTL, und die IP/CIDR ist bereits in der eBPF-Karte vorhanden.
| Path | Median latency |
|---|---|
| Normale Socket-Verbindung, kein eBPF | ~2.647 us |
| Warme Erlaubnisliste, geschützter LPM-Treffer | ~2.691 us |
| Warme Erlaubnisliste, DNS-Exact-Host-Treffer | ~2.741 us |
| Erlaubnislisten-Fehltreffer, lokale Sperre | ~1.652 us |
Die gemessene Streuung zwischen den normalen, geschützten LPM- und DNS-Exact-Host-Verbindungspfaden liegt innerhalb der Stichprobenvarianz.
Es gibt derzeit keinen Pfad 'Kernel-Fehltreffer fragt Elternprozess'. Ein Fehlschlag der Cgroup-Erlaubnisliste wird lokal durch eBPF entschieden und sofort blockiert.
Diese Zahlen messen den DNS-Serverpfad, nicht den gewärmten Socket-Verbindungspfad.
| Path | Median latency |
|---|---|
| Proxy-Abfrage kalt, prozessinterne Richtlinienfunktion | ~31.336 us |
| Proxy-Abfrage warm | ~27.964 us |
| Erlaubnislisten-Abfrage kalt mit lokalem Upstream | ~53.510 us |
| Erlaubnislisten-Abfrage warm mit lokalem Upstream | ~53.432 us |
Kalte Zeilen synchronisieren durch die reale Anhangs-Mutationsbarriere und leeren den Benchmark-Besitzgraphen und den gefälschten Exact-Map-Snapshot zwischen den Abfragen. Der Timer läuft kontinuierlich, um die UDP-Scheduler-Lokalität zu erhalten, während ns/op die separat gemeldete fixture-reset-ns/op-Wandzeit abzieht (einschließlich eines eventuellen Nachlaufs des vorherigen Handlers, nachdem der Client sein Paket erhalten hat) und somit die aktuelle Client-Exchange misst. raw-total-ns/op meldet beide zusammen. Der Reset bewahrt die konfigurierten Richtliniendomänen und den Backing-Speicher, und der Benchmark behauptet einen physischen Exact-Map-Add pro Abfrage. Warme Zeilen initialisieren den Besitz einmal und behaupten einen physischen Add über den gesamten Lauf.
Die folgenden internen Besitz-Mikrobenchmarks sind Skalierungsdiagnostiken, keine End-to-End-DNS-Abfragepfad-Akzeptanzzeilen. Der gecachte Helfer wird nur für Tests und Benchmarks beibehalten; er kapselt jeweils einen Datensatz und wiederholt die Domänenvalidierung. Sowohl er als auch normaler Resolver-Traversal durchlaufen die Anhangs-Mutationsbarriere, während normaler Resolver-Traversal jede vollständige Antwort als eine Transaktion akzeptiert.
+------------------+ +-------------------------+ | Your Control |<------->| Daemon (per host) | | Plane (gRPC) | stream | | +------------------+ | +-------------------+ | | | DNS Server | | | | (per-attachment) | | | +-------------------+ | +-------------------------+ | +------+------+ | | TC Filter Cgroup Filter (veth, eth) (containers)
Jeder Anhang erhält eine eindeutige DNS-Adresse (Port), die vom Daemon bereitgestellt wird. Container/VMs müssen so konfiguriert sein, dass sie ihre zugewiesene DNS-Adresse verwenden; das Filtern des normalen DNS-Verkehrs von Workloads leitet diesen nicht transparent um.
### DNS-Resolver-Topologie und -Verhalten
`dns.listen_addr` muss eine konkrete IPv4- oder IPv6-Adresse identifizieren, die jeder angeschlossene Workload erreichen kann. Wildcard-Adressen werden abgelehnt, da sie nicht als Resolver-Endpunkte angekündigt werden können. Ein konfigurierter Hostname wird einmal beim Start des Daemons aufgelöst, und die resultierende konkrete IP wird für Bindung, Ankündigung, Persistenz und Filter-Bootstrap verwendet. Der Standardwert `127.0.0.1` ist nur geeignet, wenn der Workload den Netzwerk-Namespace des Daemons teilt; ein Container oder VM in einem anderen Namespace benötigt normalerweise stattdessen eine erreichbare Host-/Bridge-Adresse.```yaml
dns:
listen_addr: 10.0.0.1
port_min: 11000
port_max: 11500
# Daemon-global fallback when DnsConfig.upstream_servers is empty.
upstream: 1.1.1.1:53
# Hard daemon ceilings for each attachment's bounded DNS exact ownership.
# Zero/unset uses these defaults (max_ips_per_family instead derives from
# filter.max_dns_rule_entries).
max_ips_per_family: 4096
max_ips_per_response: 64
max_ips_per_policy_domain: 1024
max_tracked_domains: 1024
max_ownership_edges: 8192
# Rolling physical-admission/LRU mutation budget and slow-planning work
# allowance. The window is daemon-global and immutable until restart;
# DnsConfig.max_churn_units may only lower the daemon ceiling.
max_churn_units: 8192
churn_window: 1m
Attach returns the concrete dns_address; konfiguriere diese genaue Adresse als
Resolver der Workload. Netfence installiert einen geschützten, nicht ablaufenden /32- oder
/128-Allow-Eintrag für die Listener-IP, sodass der Allowlist-Modus ohne
eine Kontrollebenen-DNS-IP-Regel bootstrappen kann. Die aktuellen Filter erzwingen IP-Präfixe, nicht
Zielports, sodass dieser geschützte Eintrag jeden Port auf der Listener-IP erlaubt
(nicht nur ihren DNS-Port); dies ist besonders wichtig für Threat-Modelle mit
Cgroup-Anbindung. Verwende eine dedizierte Listener-IP, wenn diese breitere Erreichbarkeit
nicht akzeptabel ist.
Der zugewiesene Endpunkt bedient sowohl UDP als auch TCP. UDP-Antworten werden auf das
512-Byte-Limit eines Legacy-Clients oder seine beworbene EDNS-Größe gekürzt und tragen
TC, wenn nötig, sodass die Workload denselben Endpunkt über TCP wiederholen kann.
Bei der Upstream-Auflösung wird eine gekürzte UDP-Antwort zunächst über TCP gegenüber demselben
Upstream wiederholt. Ein Transportfehler, SERVFAIL oder REFUSED wechselt dann
zum nächsten konfigurierten Upstream in der Reihenfolge.
DnsConfig.upstream_servers überschreibt den Daemon-globalen dns.upstream für eine
Anbindung. Einträge verwenden die Syntax host:port (IPv6-Literale in Klammern),
werden kanonikalisiert und in der Reihenfolge des ersten Auftretens dedupliziert und sind auf acht
eindeutige Server begrenzt. Eine leere Liste wählt den globalen Fallback.
In Filtermodi entfernt Netfence die Parameter ipv4hint und ipv6hint aus
HTTPS/SVCB-Antworten, einschließlich ihrer entsprechenden mandatory-Referenzen,
da angezeigte Adressen nicht unabhängig die Filterzulassung bestanden haben.
Der deaktivierte Modus gibt Upstream-Antworten unverändert weiter.
DNS-Abfragezähler schließen sich gegenseitig aus: dns_queries_allowed zählt
erfolgreich beantwortete, richtlinien-zugelassene Abfragen (einschließlich NXDOMAIN),
dns_queries_blocked zählt Richtlinien-REFUSED-Antworten, und
dns_queries_errors zählt Resolver-, Proxy-, Filterzulassungs-, Antwort-Schreib-
und andere Fehlerpfade. Eine Abfrage erhöht genau einen Bucket.
Jede adressentragende Antwort in einem DNS-Filtermodus wird der
exakten IPv4/IPv6-HASH-Stufe der Anbindung als eine Transaktion zugeführt, bevor eine A/AAAA-Adresse
aus ihren Antwort-, Autoritäts- oder Zusatzabschnitten zurückgegeben wird. Wenn
die vollständige Antwort nicht dargestellt werden kann, gibt der Resolver SERVFAIL
ohne Adresse zurück und bewahrt den zuvor zugelassenen Arbeitssatz. PROXY-Entscheidungen, die Adressen zurückgeben, müssen add_to_filter setzen; andernfalls schlagen sie ebenfalls
als SERVFAIL fehl. Der deaktivierte DNS-Modus ist die explizite Durchlass-
Ausnahme.
Exakte Einträge tragen TTL-Kanten von der normalisierten Abfrage zum übereinstimmenden Richtlinien-Besitzer. Das Entfernen oder Verweigern einer Domain entfernt schnell ihre letzten reinen DNS-exakten Adressen, während eine gemeinsam genutzte Adresse einen anderen live-Abfrage-Besitzer überlebt und eine überlappende Kontrollebenen-CIDR unabhängig in der geschützten LPM-Stufe fortbesteht. DNS-DENYLIST-Standard-Zulassungs- und explizite Zulassungsantworten werden ebenfalls verfolgt, selbst während Paket-DENYLIST exakte Zulassungen ignoriert, sodass ein späterer Paketmodus-Wechsel zu ALLOWLIST bereits zurückgegebene gecachte Adressen ohne erneute Abfrage nutzen kann.
Der gesamte normale/live-Userspace-Besitzstatus wird durch die fünf Besitzer-Einstellungen oben begrenzt.
Wiederhergestellte synthetische provisorische Kanten sind von diesen logischen Grenzen
ausgenommen, sodass sie vor der Rekonziliation nicht vergessen werden können, bleiben aber
durch die physischen IPv4/IPv6-exakten Maps begrenzt. Konfigurierte Richtlinien-Domains und
live-Abfrage-Domains teilen sich
max_tracked_domains, und jeder (Abfrage, übereinstimmender Besitzer, IP)-TTL-Eintrag verbraucht
einen max_ownership_edges-Slot.
Bei Druck projiziert die Zulassung zuerst abgelaufene TTL-Kanten weg. Sie beansprucht dann
vollständige logische Abfrage/Besitzer-Kanten mit dem geringsten physischen Kollateral zurück,
gefolgt von deterministischem, vom Resolver beobachtetem LRU (kanonische IP bricht
Gleichstände). Eine physische Räumung entfernt den gesamten DNS-exakten Schlüssel und alle seine DNS-
Besitzer. Die eingehende physische IP und die exakte eingehende (IP, Abfrage, Besitzer)-Kante
sind für die Antworttransaktion geschützt. Wiederhergestellter provisorischer Besitz
schützt seinen physischen Schlüssel bis zur autoritativen Rekonziliation, aber nicht verwandte
normale DNS-Metadaten, die diesen Schlüssel teilen, können dennoch zurückgefordert werden.
Autoritative Kontrollebenen-/System-Zulassungen und jede Verweigerung bleiben in separaten
LPM-Stufen und sind niemals Kandidaten für die DNS-Rückforderung.
Das rollierende Churn-Budget pro Anbindung berechnet eine Einheit für einen neuen physischen
exakten Schlüssel und eine für jeden geräumten live-physischen DNS-Schlüssel; ein vollständiger
Alt/Neu-Ersatz kostet daher zwei. Aktualisierungen, logische Rückforderung, Ablauf
und Richtlinienentfernung kosten null. Ereignisse bleiben aktiv, solange ihr Alter kleiner als
dns.churn_window ist, und laufen an der genauen Grenze ab. DnsConfig.max_churn_units
darf nur die Daemon-Obergrenze senken; Null übernimmt sie. Das Fenster kann nicht
von der Kontrollebene geändert werden, und das Ändern der Daemon-Obergrenze/des Fensters erfordert
einen Neustart. Das Senken und spätere Anheben einer Anbindungsgrenze vergisst nicht
noch aktive Historie.
Ein separates rollierendes Arbeitsbuch begrenzt aufwändige Besitzgraph-Planung.
Schnelle Aktualisierungen und gewöhnliche Zulassungen berühren es nie. Bevor ein Druckpfad
den Graphen klont oder analysiert, berechnet Netfence stabile Arbeitseinheiten, die von
aktuellen physischen Schlüsseln, Besitzkanten, verfolgten Domains und Antwortgröße relativ zu
ihren unveränderlichen Daemon/Map-Obergrenzen abgeleitet sind. Dieser Versuchsaufwand wird beibehalten, selbst wenn
der Plan sich als unmöglich erweist oder eine spätere Exakt-Map-Transaktion fehlschlägt, wodurch der
Null-Mutations-Wiederholungspfad für CPU-/Allokationsdruck geschlossen wird, ohne die
transaktionale physische Churn-Abrechnung oben zu ändern. Bei den Standard-Obergrenzen
lässt die Zulassung acht maximalequivalente Graph-Durchläufe pro Fenster zu; das Senken
von DnsConfig.max_churn_units behält mindestens einen. Das Senken und spätere Anheben der
Grenze skaliert nie neu oder vergisst aktive Arbeitshistorie.
Wenn kein geeigneter DNS-Zustand eine Grenze erfüllen kann oder eine der beiden rollierenden
Zulassungen erschöpft ist, bewahrt Netfence den zugelassenen Arbeitssatz und gibt SERVFAIL
zurück, ohne die nicht zugelassene Adresse zurückzugeben. Kapazitätsfehler erhöhen
map_full_drops; physische Churn- und Planungsarbeits-Drosselungen tun dies nicht. Heartbeats
zeigen Exakt-Map-Aktuell-, Kapazitäts- und Prozessgenerations-Höchstwerte
plus kumulative DNS-LRU-Räumungen, alle Zulassungsfehler und einen aggregierten
Budget-Drosselungszähler, der beide rollierenden Wächter abdeckt. Kapazitäts-, physische Budget-
und Arbeitsbudget-Druck/Wiederherstellungslogs sind unabhängig ratenbegrenzt.
Betreiber können auf TTL-/Fenster-Wiederherstellung warten, Antwort-/Domain-Churn oder
wiederholte Kapazitätsdruckversuche reduzieren oder DnsConfig.max_churn_units bis zur
Daemon-dns.max_churn_units-Obergrenze erhöhen. Das Anheben der Daemon-Obergrenze erfordert einen
Neustart; das Erhöhen von filter.max_dns_rule_entries erfordert ebenfalls das Neuerstellen der
Anbindung, da gepinnte Maps nicht vor Ort vergrößert werden können.
Autoritative Kontrollebenen-CIDRs und Daemon-Systemregeln verwenden vier unabhängige,
nicht räumbare LPM-Maps: Allow/Deny × IPv4/IPv6. Jede Map hat
filter.max_rule_entries Slots. Der DNS-Listener-/32- oder /128-Bootstrap ist ein
System-Allow und wird gegen die entsprechende geschützte Allow-Map gezählt. DNS-Exakt-Host-Einträge bleiben in ihren separaten Maps und können diese Slots
nicht verbrauchen. Keine geschützte Regel wird jemals LRU-geräumt: explizite Allows,
Systemregeln und jede Deny bleiben bis zu einer autorisierten Entfernung oder einem vollständigen Ersatz.
Ein vollständiges SubscribedAck oder BulkUpdate wird kanonikalisiert, und seine endgültige
Belegung wird für alle vier Maps vor der Mutation geprüft. Die Kapazität basiert auf dem
endgültigen Zustand, sodass das Ersetzen von Schlüsseln in einer vollen Map gültig ist; ein zu großer Zustand wird
zurückgewiesen, ohne Regeln zu räumen oder teilweise zu akzeptieren. Überlebende werden nicht
entfernt und neu hinzugefügt. Wenn ein späterer Map-Syscall fehlschlägt, stellt Netfence das
exakte Vier-Map-Inventar vor dem Aufruf wieder her und verifiziert es. Der bewiesene Modus nach dem Rollback
ist der alte Modus oder BLOCK_ALL (normalerweise BLOCK_ALL), sodass der Daemon die
Anbindung weiterhin im Fail-Closed-Zustand hält, bis ein vollständiger autoritativer Wiederholungsversuch erfolgreich ist.
Der Sicherheitszustand der geschützten Richtlinie wird mit der Anbindung persistiert und in
Heartbeats exportiert. BLOCK_ALL allein ist ein normaler, gesunder konfigurierter Modus:
policy_degraded ist false, wenn policy_degraded_reason leer ist. Eine riskante
geschützte Mutation, die startet, während BLOCK_ALL gesund ist, journalliert zuerst
protected_policy_mutation_in_progress. Dies ist ein transientes Absturzjournal, nicht
eine stabile Fehlerdiagnose: die Live-Operation kann ihre beabsichtigte Art
vor dem endgültigen Journal-Clear-Speichern veröffentlichen, und der erfolgreiche Abschluss löscht das
Journal selbst. Wenn der Start es nach einem Absturz findet, erzwingt und beweist der Start zuerst
BLOCK_ALL und persistiert dann
protected_policy_mutation_interrupted. Stabile degradierte Grundcodes sind:
protected_policy_mutation_interruptedauthoritative_protected_policy_failedincremental_deny_install_failedincremental_allow_removal_failedincremental_mode_change_failedDies sind stabile Klassifikationen, niemals roher Syscall/Store-Text. Das
laufende Journal ist eine interne persistierte Absturzgrenze; Heartbeat-Statistiken
serialisieren mit der besitzenden Mutation und beobachten daher entweder ihren erfolgreichen
Clear oder eine stabile Fehlerumwandlung, nicht das Live-Zwischenjournal.
Stabile degradierte/unterbrochene Gründe halten die Paketdurchsetzung im bewiesenen
BLOCK_ALL und lehnen inkrementelle CIDR- und Paketmodus-Befehle ab.
Unabhängige DNS-Konfigurationsänderungen und DNS-TTL-Abläufe können unter
diesem bewiesenen Halten fortgesetzt werden, können aber den stabilen Grund nicht löschen oder die Paketrichtlinie
reaktivieren. Die Wiederherstellung von einem stabilen Grund erfordert einen vollständigen LPM-und
DNS-Soll-Zustand: wende BulkUpdate über die Kontrollebene oder die lokale API an (oder
beantworte das Subscribed einer wiederhergestellten Anbindung mit SubscribedAck).
Netfence bereitet den vollständigen geschützten Zustand vor,
wendet den autoritativen DNS-Zustand an, aktiviert den angeforderten Modus und löscht
den dauerhaften Grund erst, nachdem jeder Schritt erfolgreich war. Bevorzuge eine eindeutige command_id
auf einem BulkUpdate der Kontrollebene zur Wiederherstellung und erfordere ein erfolgreiches
CommandResult; die lokale API lehnt command_id ab, da ihr unäres RPC-Ergebnis
bereits Erfolg oder Fehlschlag meldet.
Heartbeats zeigen aktuelle physische Einträge, harte Kapazität und
Daemon-Generations-Höchstwerte unabhängig für alle vier geschützten Maps. Der
Bootstrap ist enthalten; übernommene gepinnte Einträge initialisieren den Höchstwert der neuen Generation.
map_full_drops ist kumulativ und enthält geschützte Kapazitätsablehnungen. Wenn eine Belegungsablesung fehlschlägt, behält der Daemon die letzte bewiesene
Momentaufnahme und gibt höchstens einmal alle 30 Sekunden eine Warnung aus, anstatt
neue Zählwerte zu erfinden. Zur Wiederherstellung von Druck reduziere die vollständigen gewünschten Regeln unter
jeder Pro-Map-Kapazität und wiederhole das vollständige Update. Das Erhöhen von
filter.max_rule_entries ist nur zur Ladezeit möglich und erfordert das Neuerstellen einer bestehenden
gepinnten Anbindung. Wenn der Daemon BLOCK_ALL nicht beweisen oder seinen Sicherheitsmarker
dauerhaft aufzeichnen kann, stoppt er die Mutationszulassung; repariere den Map/Store-Fehler und
starte neu, anstatt anzunehmen, dass die Durchsetzung wieder geöffnet ist.
Führe den Daemon aus, welcher:
DaemonService) für Anbindungen, Richtlinien und Inspektion bereitstelltControlPlane.Connect) eine Verbindung zu deiner Kontrollebene herstelltStarte den Daemon:```bash
netfenced start
netfenced start --config /etc/netfence/config.yaml
**Daemon-Status überprüfen:**```bash
netfenced status
Mit keinem control_plane.url wird ein neuer Attachment im deaktivierten Paket-/DNS-Modus ausgeführt und kann sofort über die lokale API oder CLI konfiguriert werden. Für den unter „Per Attachment“ dokumentierten eigenständigen Workflow ist kein Control-Plane-Prozess erforderlich.
Die lokale gRPC-API hat keine Authentifizierung pro RPC. Der Dateisystemzugriff auf ihren Unix-Socket ist die Autorisierungsgrenze, und jeder Prozess, der eine Verbindung herstellen kann, ist ein vollständig vertrauenswürdiger Host-Netzwerk-Administrator: Er kann Host-eBPF-Programme anhängen oder trennen, Paket- und DNS-Richtlinien ersetzen sowie Workload-Datenverkehr öffnen oder schließen. Halten Sie die Socket-Gruppenmitgliedschaft eng und schützen Sie das übergeordnete Verzeichnis des Sockets.```yaml
socket: /run/netfence/netfence.sock
socket_group: netfence-admin
`NETFENCE_SOCKET` und `NETFENCE_SOCKET_GROUP` sind die entsprechenden Umgebungsvariablen. Beim Start bindet der Daemon den Socket in einem privaten Staging-Verzeichnis, setzt seine Gruppe und den Modus `0660`, während er unerreichbar ist, und veröffentlicht ihn dann atomar. Der Daemon entfernt jeden bereits vorhandenen Unix-Socket am konfigurierten Ziel – er unterscheidet nicht zwischen einem veralteten Socket und einem, der einem anderen laufenden Daemon gehört –, daher muss genau ein Daemon einen Socket-Pfad besitzen. Er weigert sich, ein Nicht-Socket-Ziel zu entfernen. Unter Linux verhindert das "no-replace rename" das Überschreiben eines neuen Pfads, der nach dieser Entfernung erstellt wurde; beim Herunterfahren wird der veröffentlichte Pfad nur entfernt, solange er noch den Inode des eigenen Sockets des Daemons identifiziert. Eine ungültige Gruppe, ein Besitz-/Modusfehler oder ein Nicht-Socket-Ziel führt zu einem Startfehler, ohne einen permissiven Endpunkt zu veröffentlichen.
### Sicherheit des Control-Plane-Transports (TLS / mTLS / Bearer-Token)
Der Control-Plane-Kanal ist die wertvollste Angriffsfläche im System (wer ihn kontrolliert, kann `ALLOW`-Regeln an jede Workload pushen), daher **schlägt der Daemon geschlossen fehl**: wenn `control_plane.url` gesetzt ist, muss die Konfiguration explizit einen Transport wählen – entweder einen `control_plane.tls`-Block oder `control_plane.insecure: true`. Eine URL ohne beides wird beim Start abgelehnt; es gibt keine implizite Klartext-Voreinstellung. (Dies ist eine bewusste Verhaltensänderung: ältere Versionen haben die Control-Plane unverschlüsselt angewählt.)```yaml
control_plane:
url: cp.internal:443
tls:
# CA bundle used to verify the control-plane server certificate.
# Path to a PEM file or inline PEM; omit to use the system root pool.
ca: /etc/netfence/cp-ca.pem
# Client certificate + key (path or inline PEM). Setting BOTH enables
# mTLS: the daemon presents this cert to the control plane. Setting only
# one is a config error.
cert: /etc/netfence/daemon.pem
key: /etc/netfence/daemon.key
# Optional hostname override for server certificate verification (SNI),
# e.g. when dialing by IP.
server_name: cp.internal
# Optional bearer token, sent as `authorization: Bearer <token>` metadata
# on every control-plane RPC. Refused on a plaintext channel unless
# `insecure: true` was explicitly set (so a misconfiguration can't leak it).
auth_token: "..."
TLS nur mit Systemstammzertifikaten (öffentliches CA-ausgestelltes Serverzertifikat, kein mTLS) ist nur ein leerer Block:```yaml control_plane: url: cp.example.com:443 tls: {}
Plaintext für lokale Entwicklung ist ein explizites Opt-in (sich gegenseitig ausschließend mit `tls`):```yaml
control_plane:
url: localhost:9000
insecure: true
Zertifikate und Schlüssel werden einmalig beim Start geladen, sodass ein falscher Pfad/ein ungültiges PEM mit einer klaren Fehlermeldung fehlschlägt, anstatt bei jeder erneuten Verbindung aufzutauchen.
Der Daemon sendet HTTP/2-Keepalive-Pings auf der Control-Plane-Verbindung, sodass ein stiller Verbindungsabbruch (Kabelziehen, verlorene NAT-Zuordnung, Blackhole-Route) erkannt und in etwa keepalive_time + keepalive_timeout abgerissen wird – anstatt Minuten lang im Zustand CONNECTED zu verharren, bis das TCP-Retransmission-Timeout des Kernels abläuft, während jede proxierte DNS-Anfrage ihre vollständige Timeout-Zeit verbraucht. Wiederherstellungsversuche werden durch einen exponentiellen Backoff mit Jitter getaktet (beginnt bei 1s, verdoppelt sich, ±20% Jitter, begrenzt auf reconnect_backoff_max); der Backoff wird nur auf den Startwert zurückgesetzt, nachdem eine Verbindung 30s lang gesund geblieben ist, sodass eine Steuerungsebene, die Verbindungen akzeptiert und sofort verwirft, den Backoff weiter erhöht, anstatt ständig auf den Startwert zurückgesetzt zu werden.```yaml
control_plane:
keepalive_time: 30s
keepalive_timeout: 10s
reconnect_backoff_max: 30s
Null- oder nicht gesetzte Werte bedeuten die Standardwerte – sie deaktivieren **nicht** Keepalive oder den Backoff. Ihre Kontrollebene muss diesen Ping-Rhythmus in ihrer gRPC-Keepalive-Durchsetzungsrichtlinie erlauben (siehe unten), sonst wird sie den Daemon mit `ENHANCE_YOUR_CALM (too_many_pings)` ablehnen.
### Neustarts, Abstürze und Upgrades des Daemons (angehefteter BPF-Zustand)
Der Daemon heftet die BPF-Links und Regelzuordnungen jedes Attachments an bpffs an (`filter.bpf_pin_dir`, standardmäßig `/sys/fs/bpf/netfence`, ein Verzeichnis pro Attachment-ID). Da der angeheftete Zustand vom Kernel gehalten wird – nicht vom Daemon-Prozess – **läuft die Durchsetzung weiter, während der Daemon nicht läuft**: Ein Absturz (`kill -9`), ein ordentlicher Stopp oder ein Upgrade hinterlässt die zuletzt bekannte Richtlinie (Modus + alle Regeln) in Kraft, und der nächste Daemon-Start übernimmt den angehefteten Zustand unverändert. Die Wiederherstellung fügt keine Live-Maps erneut an oder überschreibt sie, sodass es kein Fenster gibt, in dem eine zugelassene Arbeitslast blockiert oder ein blockiertes Ziel zugelassen wird, und es gibt keine doppelten Attachments.
Das Stoppverhalten ist explizit konfiguriert (`filter.detach_on_stop`):```yaml
filter:
# false (default): stopping the daemon KEEPS ENFORCING — filters stay
# attached via their bpffs pins and are re-adopted on the next start
# (fail-closed across restarts/upgrades).
# true: stopping the daemon detaches filters and removes their pins —
# traffic is unfiltered while the daemon is down (explicit fail-open).
detach_on_stop: false
# bpffs directory for pinned state. Must be on a bpffs mount; the daemon
# mounts bpffs at /sys/fs/bpf if needed (privileged). An explicit "" turns
# pinning off entirely (BPF state then dies with the process).
bpf_pin_dir: /sys/fs/bpf/netfence
# Capacity of each authoritative/system LPM map (allowed/denied per family).
# Protected entries are non-evictable; the DNS listener bootstrap consumes
# one slot in its address family. Changing pinned-map capacity requires
# recreating the attachment.
max_rule_entries: 4096
# Independent capacity of each DNS-derived exact-host HASH map (IPv4/IPv6).
# These entries can never consume or evict authoritative/deny capacity.
max_dns_rule_entries: 4096
Ein explizites Detach (RPC/CLI) oder das Entfernen eines live kohärent eigenen Ziels zerstört den gepinnten Status zusammen mit dem Attachment. Beim Neustart autorisiert das Fehlen eines Ziels kein Raten: zukünftige, nicht festgeschriebene, gemischte oder anderweitig nicht verifizierbare persistierte Pins werden erhalten, und der Startvorgang bricht zur Überprüfung ab.
Pin-Verzeichnisse sind ein versioniertes Persistenzformat. Der Schema-Marker wird zuletzt gepinnt, erst nachdem jede erforderliche Map und jeder Link vorhanden ist. Ein Upgrade eines zuvor exakten Tier-Attachments pinnt die beiden neuen leeren exakten Maps mit einem In-Progress-Marker, ersetzt atomar das Programm jedes Links unter Wiederverwendung der live autoritativen Maps, überprüft die Programm/Map-Identität und committet den Marker zuletzt. Ein Absturz oder eine mehrdeutige Aktualisierung hinterlässt den Marker nicht committet; der nächste Start aktualisiert jeden Link mit denselben Maps erneut. Alte und neue Programm-Generationen erzwingen während dieses begrenzten Mischzustands dieselbe autoritative LPM-Richtlinie, sodass eine Migration niemals einen brauchbaren Filter entpinnt oder neu erstellt. Unbekannte, unvollständige oder nicht verifizierbare Pin-Sets werden erhalten und brechen den Startvorgang zur Überprüfung ab, anstatt geraten zu werden.
Anmerkungen zum neu übernommenen Zustand:
SyncRequest, dann eine vollständige Subscribed-Deklaration für jedes wiederhergestellte Attachment, das noch einer Abgleichung bedarf. Antworte mit einer frischen SubscribedAck: Deren Modus, CIDRs, TTLs und DNS-Konfiguration sind der vollständige Soll-Zustand. Der Daemon wendet ein Delta an (unveränderte CIDRs werden nie entfernt) und löscht den Wiederherstellungsmarker erst, nachdem das gesamte Ack angewendet wurde. Ein Timeout, ein Verbindungsabbruch oder ein Validierungsfehler lassen die Durchsetzung unverändert. Ein Filter-/Map-/DNS-/Store-Anwendungsfehler kann ein partielles Delta hinterlassen, aber der Abgleich verwendet kein vollständiges Map-Clear oder Entfernen/Neu-Hinzufügen von unveränderten Überlebenden; der Wiederherstellungsmarker bleibt gesetzt, und der Daemon wiederholt nach einer späteren Verbindung.SubscribedAck eintrifft; dieses autoritative Ack ersetzt ihre Lebensdauern exakt, einschließlich der Verkürzung einer Frist oder der Rückwandlung einer vorläufig permanenten Regel in eine Regel mit endlicher TTL. Wiederhergestellte exakte DNS-Schlüssel werden inventarisiert und durch begrenzte vorläufige Besitzer dargestellt (die tatsächlichen gepinnten Map-Kapazitäten sind die Grenze); die erste autoritative DNS-Konfiguration verwirft jede synthetische Behauptung, entfernt Schlüssel, die besitzerlos geblieben sind, und bewahrt einen Schlüssel nur, wenn er separat einen normalen live Besitzer hat. Ein nicht-kanonisches/kollidierendes Inventar bricht die Wiederherstellung ab, ohne Besitzmetadaten zu erraten oder teilweise zu veröffentlichen.Ihr Orchestrierungssystem ruft die lokale API des Daemons auf.
RPC:``` DaemonService.Attach(interface_name: "veth123", tc_direction: TC_DIRECTION_INGRESS, metadata: {vm_id: "abc"}) // or DaemonService.Attach(cgroup_path: "/sys/fs/cgroup/...", metadata: {container_id: "xyz"})
**CLI:**```bash
# Attach to a host-side veth peer or VM tap (TC) - use ingress direction
netfenced attach --interface veth123 --direction ingress --metadata vm_id=abc
# Attach to a cgroup
netfenced attach --cgroup /sys/fs/cgroup/... --metadata container_id=xyz
# Attach to an uplink inside the workload's own netns (TC) - egress is the default
netfenced attach --interface eth0 --metadata tenant=acme,env=prod
TC-Richtung: Das Feld tc_direction (CLI --direction) wählt aus, an welchen TCX-Hook der Filter angehängt wird. Die richtige Wahl hängt davon ab, auf welcher Seite der Verbindung sich das Interface befindet:
Die Richtung gilt nur für Interface (TC)-Bindungen; sie wird bei Cgroup-Bindungen ignoriert.
control_plane.url konfiguriert ist, sendet der Daemon Subscribed{id, target, type, metadata} und wartet auf SubscribedAck mit der initialen Konfiguration (Modus, CIDRs, DNS-Regeln). Wenn die Kontrollebene nicht innerhalb des Timeouts (Standard 5s, konfigurierbar über control_plane.subscribe_ack_timeout) antwortet, wird die Bindung zurückgesetzt und der Aufruf von Attach schlägt fehl. Validierungs- und andere Pre-Commit-Fehler folgen der gleichen normalen Rollback-Regel.Attach sofort im deaktivierten Modus ausgeführt; verwenden Sie die folgenden lokalen Policy-Befehle, um es zu konfigurieren.BLOCK_ALL bei, anstatt sie zerstörend zurückzusetzen. Mit einem begrenzten Timeout gibt Attach einen Fehler zurück, der die beibehaltene Bindungs-ID enthält; der Aufrufer kann diese ID durch Abgleich des Ziels in List finden, und die Kontrollebene muss sie mit einem vollständigen BulkUpdate wiederherstellen.RPC:``` DaemonService.Detach(id)
**CLI:**```bash
netfenced detach --id <attachment-id>
Anhänge auflisten:```bash netfenced list netfenced list --all # fetch all pages
### Lokale Richtlinie und Inspektion
Jede lokale Mutation ist eine dünne CLI-Codierung des einzelnen
`DaemonService.ApplyCommand(ControlCommand)` RPC. Geben Sie die von `attach` zurückgegebene Anhang-ID an:```bash
# Packet policy and protected CIDRs.
netfenced set-mode <id> allowlist
netfenced allow-cidr <id> 10.0.0.0/8
netfenced allow-cidr <id> 192.0.2.10/32 --ttl 5m
netfenced deny-cidr <id> 10.20.0.0/16
netfenced remove-cidr <id> 10.20.0.0/16 --list deny
# --list accepts allow, deny, or both (the default).
# DNS policy.
netfenced set-dns-mode <id> denylist
netfenced allow-domain <id> example.com --subdomains
netfenced deny-domain <id> blocked.example.com
netfenced remove-domain <id> blocked.example.com
# Deterministic current-policy inspection as protobuf JSON.
netfenced rules <id>
Paket-Modi sind disabled, allowlist, denylist und block-all; DNS-Modi
sind disabled, allowlist, denylist und proxy. DNS proxy erfordert eine
erreichbare konfigurierte Steuerungsebene. Domain-Matching verwendet das
spezifischste passende Suffix; wenn gleich spezifische Allow- und Deny-Regeln
beide übereinstimmen, gewinnt Deny. CIDRs und Domains werden kanonisiert.
Negative, fehlerhafte oder anderweitig ungültige TTLs, Enums, CIDRs, Domains,
Selektoren und verschachtelte Nachrichten werden vor der Mutation abgelehnt,
sodass ein ungültiger Befehl eine Nulloperation der Richtlinie ist.
Für einen vollständigen Austausch liest apply-rules die vorhandene BulkUpdate-Protobuf-JSON-Struktur aus einer Datei oder stdin:```bash
cat >rules.json <<'JSON'
{
"mode": "POLICY_MODE_ALLOWLIST",
"allowCidrs": [{"cidr": "10.0.0.0/8"}],
"dns": {
"mode": "DNS_MODE_DENYLIST",
"denyDomains": [{"domain": "blocked.example.com", "includeSubdomains": true}]
}
}
JSON
netfenced apply-rules --file rules.json
netfenced apply-rules --file - < rules.json
`ApplyCommand` akzeptiert nur `SetMode`, `AllowCIDR`, `DenyCIDR`, `RemoveCIDR`,
`BulkUpdate`, `SetDnsMode`, `AllowDomain`, `DenyDomain` und `RemoveDomain`.
Nur-Stream-Sync/Ack-Varianten, unbekannte oder leere Befehle sowie lokale
`command_id`-Werte werden abgelehnt. `BulkUpdate` ist außerdem die einzige lokale Operation,
die eine stabile degradierte Paketrichtlinie wiederherstellen kann; sie muss den vollständigen
gewünschten LPM- und DNS-Zustand enthalten.
Der optionale Selektor `ControlCommand.remove_cidr_list` kann die Erlaubnisliste,
die Verbotsliste oder beide anvisieren, wenn die Befehlsvariante `RemoveCIDR` ist. Der veraltete
nicht spezifizierte Wert und der explizite Wert `BOTH` entfernen beide aus beiden Listen, wodurch
das ursprüngliche Protokollverhalten erhalten bleibt.
Lokale und Kontrollplan-Mutationen teilen sich einen Parser, eine Mutationsbarriere, ein TTL-
Register, einen Fail-Closed-Wiederherstellungspfad und einen Policenbesitzer. Es gibt bewusst keine
Schlichtung der Besitzverhältnisse zwischen lokalem und Kontrollplan: widersprüchliche Operationen auf
einer einzelnen Policenliste werden in ihrer committeten Reihenfolge wirksam, unabhängig von der
Quelle. Insbesondere kann ein späterer vollständiger Kontrollplan-`BulkUpdate` oder
`SubscribedAck` den lokalen Zustand ersetzen.
`GetRules`/`netfenced rules` gibt einen kohärenten, deterministischen Userspace-
Registry-Snapshot zurück. Jedes CIDR meldet Erlaubnis-/Verbotsliste, `policyOwned` (lokal oder Kontrollplan),
`systemOwned` (Daemon), absolute `expiresAt`, wiederhergestelltes `provisional` und den zuletzt committeten
Kernelzustand `installed`. Ein installierter Eintrag ohne Besitzer ist ein fehlgeschlagener Entfernungsversuch,
keine gewünschte Richtlinie. Die DNS-Ausgabe ist die lebende, normalisierte effektive `DnsConfig`. Die Inspektion
zählt bewusst nicht geschützte Kernel-Maps auf und legt auch keine dynamisch aufgelösten DNS-Exact-Host-
Cache-Einträge offen; verwenden Sie Heartbeat-Telemetrie für die Auslastung der geschützten Maps.
## Auf der Kontrollebene (Sie implementieren dies)
Implementieren Sie den `ControlPlane.Connect` RPC - einen bidirektionalen Stream:
Konfigurieren Sie die Keepalive-Durchsetzungsrichtlinie Ihres gRPC-Servers, um den
Ping-Rhythmus des Daemons zu erlauben (`control_plane.keepalive_time`, Standard 30s): setzen Sie
`MinTime` auf oder unter dieses Intervall und `PermitWithoutStream: true`. Die gRPC-
Standardrichtlinie (5 Minuten) behandelt die Pings des Daemons als missbräuchlich und schließt
die Verbindung mit `ENHANCE_YOUR_CALM (too_many_pings)`. In Go:```go
grpc.NewServer(grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
MinTime: 10 * time.Second,
PermitWithoutStream: true,
}))
Empfang vom Daemon:
SyncRequest bei Verbindung/Wiederverbindung (listet aktuelle Anhänge auf)Subscribed wenn neue Anhänge hinzugefügt werden, und nach SyncRequest für wiederhergestellte Anhänge, die noch frische autoritative Zustände benötigenUnsubscribed wenn Anhänge entfernt werdenHeartbeat mit StatistikenCommandResult{command_id, id, success, error} — Ergebnis eines Befehls, den Sie mit einer nicht-leeren command_id gesendet haben (opt-in Korrelations-Nonce auf ControlCommand; Befehle ohne eine erzeugen kein Ergebnis). success ist nur wahr, wenn der Befehl vollständig angewendet wurde – ein teilweise angewendetes BulkUpdate meldet Fehler mit dem aggregierten Fehler. Ergebnisse sind Best-Effort: Behandeln Sie ein fehlendes Ergebnis als unbekannt, nicht als fehlgeschlagen.Senden an den Daemon:
SyncAck nach Empfang von SyncRequestSubscribedAck{mode, cidrs, dns_config} nach Empfang von Subscribed (erforderlich – Daemon wartet darauf)SetMode{mode} – IP-Filterrichtlinienmodus ändernAllowCIDR{cidr, ttl} / DenyCIDR / RemoveCIDR (optional select
allow, deny oder both; nicht angegeben behält das Legacy-„both“-Verhalten bei)SetDnsMode{mode} – DNS-Filtermodus ändernAllowDomain{domain} / DenyDomain / RemoveDomain (der spezifischste Treffer gewinnt; verweigern gewinnt bei gleich spezifischem Treffer)BulkUpdate{mode, cidrs, dns_config} – vollständige ZustandssynchronisationWenn die Steuerungsebene Subscribed empfängt, muss sie mit einem vollständigen
SubscribedAck antworten. Bei einem neuen Anhang wartet der Daemon normalerweise auf dieses Ack,
bevor er dem lokalen Aufrufer Erfolg meldet. Bei einem wiederhergestellten Anhang
läuft der Handshake im Hintergrund, während die gespeicherte letzte bekannte Richtlinie weiterhin gilt.
Verwenden Sie die Metadaten, um die VM/den Mandanten/den Container zu identifizieren, und geben Sie den
vollständig gewünschten Modus, CIDRs (einschließlich TTLs) und DNS-Status zurück; eine ausgelassene DNS-Konfiguration bedeutet deaktiviert mit leeren Domain-Listen.
SyncRequest ist der autoritative Abgleichspunkt: Bei jeder
(Wieder-)Verbindung ist es das erste Ereignis im Stream und listet den gesamten aktuellen Anhangssatz des Daemons auf. Gleichen Sie Ihre Ansicht damit ab – fügen Sie Anhänge hinzu, die Sie nicht kannten, entfernen Sie diejenigen, die nicht in der Liste sind. Bei
Wiederverbindung löscht der Daemon Ereignisse, die gegen die vorherige Verbindung in der Warteschlange waren (die Synchronisation überschreibt sie), sodass Sie keine veralteten
Heartbeats, Unsubscribeds für Anhänge, die bereits in der Synchronisation fehlen,
oder CommandResults der toten Verbindung, die danach wiedergegeben werden, sehen. Zwei Grenzfälle
bleiben absichtlich bestehen, und Ihre Steuerungsebene MUSS sie idempotent
behandeln:
Subscribed kann auf ein SyncRequest folgen, das bereits dieselbe ID auflistet.
Dies passiert, wenn ein Ack eines neuen Anhangs über eine Wiederverbindung hinweg ausstehend war, und
bewusst für jeden wiederhergestellten Anhang, bis ein autoritatives Ack vollständig angewendet wird. Behandeln Sie es als Update, antworten Sie mit einem frischen vollständigen
SubscribedAck, und verwerfen Sie es niemals als Duplikat. SyncRequest
gleicht den Anhangsbestand ab; SubscribedAck gleicht die gewünschte Richtlinie ab.Unsubscribed für eine unbekannte oder bereits entfernte Anhang-ID als No-Op.AllowCIDR/DenyCIDR-Befehle und die CIDR-Listen in SubscribedAck/BulkUpdate) tragen eine optionale TTL. TTL-basierte Regeln werden von einem Daemon-Janitor entfernt, sobald sie ablaufen (Scan-Intervall ttl_janitor_interval, Standard 1s); Regeln ohne TTL sind dauerhaft.AllowCIDR/DenyCIDR-Neuhinzufügungen verlängern eine CIDR bis zur späteren Frist – sie verkürzen niemals eine – und eine inkrementelle Neuhinzufügung ohne TTL macht sie dauerhaft. Im Gegensatz dazu ersetzt der vollständige Zustand in SubscribedAck/BulkUpdate jede Lebensdauer der Steuerungsebene genau, sodass autoritativer Abgleich eine TTL verkürzen oder dauerhaft in endlich ändern kann, ohne den Live-Map-Eintrag zu entfernen/neu hinzuzufügen. Verwenden Sie RemoveCIDR, um eine inkrementelle Regel vorzeitig zu entfernen.dns.min_filter_ttl (Standard 60s; null/nicht gesetzt bedeutet den Standard, nicht „keine Untergrenze“). Eine vorgelagerte TTL von Null lebt daher für die Untergrenze; eine ausgelassene PROXY-TTL wird explizit auf 300s standardmäßig gesetzt, bevor die Untergrenze angewendet wird. Eine dauerhafte oder längerlebige CIDR-Regel, die dieselbe Adresse abdeckt, bleibt unabhängig in der geschützten LPM-Ebene installiert, wenn die genaue DNS-Besitzerzeit abläuft.| Internal scalability diagnostic | Current median | Memory / allocations |
|---|
| Kalte Neuaufnahme eines Schlüssels, leerer Besitzgraph | ~370.3 ns | 232 B, 5 allocs/op |
| Kalte Neuaufnahme eines Schlüssels, 4.095 nicht verwandte Einträge | ~451.2 ns | 232 B, 5 allocs/op |
| Physischer Kapazitätsdruck und LRU-Ersatz | ~3.820 ms | ~4.23 MB (4,226,243 B), 4,336 allocs/op |
| Vorabprüfung des erschöpften physischen Budgets | ~611.9 ns | 344 B, 9 allocs/op |
| Maximaler Kantendruck, 64-Adress-Antwort | ~6.849 ms | ~7.66 MB (7,658,774 B), 2,233 allocs/op |
| Maximaler Graph-Arbeitswächter, erlaubter vollständiger Plan | ~2.763 ms | ~4.26 MB (4,264,386 B), 3,074 allocs/op |
| Maximaler Graph-Arbeitswächter, erschöpfte Vorprojektionsablehnung | ~10.935 us | 8.76 KB (8,760 B), 14 allocs/op |
| Churn-Budget-Operation nahe der numerischen Obergrenze | ~18.98 ns | 0 B, 0 allocs/op |
| Kohärenter Besitz-Statistik-Snapshot | ~2.094 ns | 0 B, 0 allocs/op |
| No-op-Ablaufscan über 4.095 Einträge | ~74.849 us/scan | 0 B, 0 allocs/op |
netfenced apply-rulesREFUSED zurück, bis eine vollständige BulkUpdate oder SubscribedAck angewendet wird. Ein explizit DISABLED-DNS-Modus leitet weiterhin weiter. Wenn später einer der festgeschriebenen UDP/TCP-Listener unerwartet stirbt, wird das Attachment im IP-BLOCK_ALL-Modus unter Quarantäne gestellt und als Fehler-Unsubscribe gemeldet.| Interface | Richtige Richtung | Begründung |
|---|
Uplink (z. B. eth0) oder ein beliebiges Interface im eigenen Netns der Workload | egress (Standard) | Die ausgehenden Pakete der Workload werden darüber gesendet; ihre Zieladresse ist das tatsächliche Ziel. |
Hostseitiger Veth-Peer oder VM-Tap (z. B. fcr-*) | ingress | Die ausgehenden Pakete der Workload treffen auf diesem Interface auf dem Host ein. Egress würde dort stattdessen den Rückverkehr Host→Workload sehen und nach der eigenen Adresse der Workload statt dem tatsächlichen Ziel filtern. |
subscribe_ack_timeout: 0 kehrt ein neuer Attach zurück, nachdem Subscribed in die Warteschlange gestellt wurde; ein späteres Ack wird dennoch validiert und angewendet. Dieser Nullwert deaktiviert nicht die Wiederherstellungskonvergenz wiederhergestellter Bindungen: Wiederherstellungsversuche warten bis zu 5 s im Hintergrund und wiederholen bei einer späteren Verbindung, falls nötig. Wenn dieses spätere Ack auf Druck der geschützten Map trifft, wird die bereits zurückgegebene Bindung in BLOCK_ALL beibehalten; SubscribedAck sendet weder CommandResult noch ein Fehler-Unsubscribed, und der Daemon fährt die Deklaration vor dem Neustart nicht automatisch erneut. Erkennen Sie policy_degraded plus dessen Grund, Belegung/Kapazität und map_full_drops in Heartbeat, senden Sie dann ein vollständiges BulkUpdate mit command_id, um ein explizites Wiederherstellungsergebnis zu erhalten.Unsubscribed.filter.max_rule_entries pro Anhang (Standard 4096 jeweils); siehe „Geschützte CIDR-Kapazität und Fail-Closed-Wiederherstellung“ oben. DNS-abgeleitete Hostadressen verwenden separate exakte HASH-Maps, dimensioniert durch filter.max_dns_rule_entries (Standard 4096 pro IP-Familie), sodass sie autoritative oder Deny-Kapazität weder verbrauchen noch verdrängen können. Die vollständige DNS-Antwortannahme validiert/kanonisiert jede Adresse und prüft physische und logische Kapazität vor der Mutation. Ein Kernel-Fehler der exakten DNS-Map stellt ihre exakte Voraufruf-Momentaufnahme wieder her; wenn dieses Rollback nicht nachgewiesen werden kann, unterdrückt der Resolver die Antwort und isoliert den Anhang in dauerhafter IP BLOCK_ALL, bevor er eine weitere Mutation akzeptiert.