feat: enhance networking capabilities with improved egress handling and automatic host sharing rules

This commit is contained in:
2026-09-23 06:23:49 +05:30
parent 534a78f2a9
commit ed9c5306af
3 changed files with 110 additions and 38 deletions
+38 -18
View File
@@ -373,8 +373,10 @@ not needed. It never recopies the rootfs, reprovisions credentials, or
regenerates guest SSH host keys. Name/IP/MAC, ports, and guest disk changes
survive stop/start; guest RAM does not.
Start on a healthy running VM synchronizes policy without spawning another
VMM. An ambiguous process or interrupted live boot/stop is not adopted as a
Start on a healthy running VM validates its retained network, synchronizes
policy, then restores shared bridge/NAT/forwarding rules without spawning another
VMM. A shared-network setup failure retains the running VM for retry. An ambiguous
process or interrupted live boot/stop is not adopted as a
successful start. Failed resume retains the private disk for retry. Restart
performs stop and start under one operation lock, not two independent public
calls with a race between them.
@@ -605,7 +607,7 @@ Linux bridge: uvm0 (10.42.0.1/24 by default)
|
iptables forwarding + MASQUERADE
|
host default uplink
host IPv4 route for the destination (current uplink)
|
internet
```
@@ -620,7 +622,7 @@ internet
- Bridge creation or validation that an existing interface is actually a
Linux bridge.
- Gateway address setup and IPv4 forwarding.
- One egress NAT rule and forward/return rules for the default uplink.
- Egress NAT and forward/return rules scoped to the guest subnet/bridge.
- TAP ownership aliases (`uvm:<id>`), preparation while down, activation,
deactivation, cleanup, and error reporting.
@@ -629,6 +631,23 @@ it may belong to another VM. A create-time name collision is an error. Cleanup
checks the TAP kind and ownership alias, with a narrow unaliased-TAP allowance
for legacy records; it does not treat an arbitrary interface name as ownership.
Internet sharing is configured even with no host default route. Rules never
pin an uplink interface: Linux routing selects it, and MASQUERADE uses that
interface's address. Offline-to-online transitions, reconnects and route changes
therefore work without another UVM command or a monitoring daemon. Existing
connections may need to reconnect after the upstream address changes. Guest
DNS in the Ubuntu template uses the public resolvers documented in README.
`uvm-egress`-commented iptables rules are checked before insertion, with a bounded
xtables-lock wait. Scoped exceptions are inserted at the start of the host chains
so pre-existing terminal drops cannot shadow them. Outbound forwarding requires
the UVM bridge and source subnet; routed replies require the destination bridge,
subnet and established/related conntrack state. Native bridge policy still checks
identity, service ports and permitted protocols. Outbound forwarding also covers
peer traffic if the host already uses `br_netfilter`, while MASQUERADE excludes
the UVM bridge to retain private peer source addresses. Global chain policies
and unrelated rules remain administrator-owned.
### Native Bridge Policy
The supported path is a **software Linux bridge** with STP disabled. Each
@@ -685,16 +704,16 @@ including on conntrack-tools 1.4.8, where `--list` is not a supported option.
### Coexistence and Recovery
Existing `iptables` egress MASQUERADE/forwarding remains unchanged. The new
policy adds no DNAT, public listener, or host-port mapping and does not replace
the host firewall manager. Public connectivity, DNS, guest reverse proxies/TLS,
Shared `iptables` egress MASQUERADE/forwarding is separate from private bridge
policy. The policy adds no DNAT, public listener, or host-port mapping and does not replace
the host firewall manager. Public inbound connectivity, DNS publication, guest reverse proxies/TLS,
and integration with UFW/firewalld/Docker/libvirt remain out of scope. An
administrator's external routing/NAT can still affect reachability; do not
infer source-CIDR restrictions or complete public-exposure protection from the
use of private addresses. Operators must choose a non-conflicting topology.
If an external actor loses or changes UVM rules, recovery is explicit
`ports sync`, not a promised daemon repair. An `enforced` snapshot cannot
If an external actor loses or changes private policy, recovery is explicit
`ports sync`; `start` also restores shared networking for a running VM. An `enforced` snapshot cannot
prevent later root-level changes or prove that other rules allow traffic.
[FIREWALL.md](FIREWALL.md) retains the original proposal/backend evaluation;
do not import its unimplemented topology checks into current documentation.
@@ -950,17 +969,18 @@ The opt-in packet harness must run **only in disposable isolated user/network
namespaces**. It verifies namespace separation before creating links or
changing rules, and never falls back to the parent host namespace. It may
require privileges (or enabled unprivileged user namespaces) plus `unshare`,
`ip`, `bridge`, `nft`, `conntrack`, and `sysctl`:
`ip`, `bridge`, `nft`, `iptables`, `conntrack`, and `sysctl`:
```sh
UVM_FIREWALL_INTEGRATION=1 python3 -B -m unittest discover -s tests/integration -v
```
The harness uses bridge-connected veths in place of guest TAPs and routed
egress without NAT. It exercises host/peer service traffic, both-direction
close of existing streams while preserving conntrack/egress, IPv6/spoof
blocking, quarantine, and offline cleanup. It does not boot a microVM or
validate real TAP/NAT deployment.
The harness uses bridge-connected veths in place of guest TAPs and two simulated
uplinks. It exercises NAT with a pre-existing terminal FORWARD drop, offline
startup, uplink changes and reconnects for host/guest TCP and guest UDP/53.
It also checks host/peer service traffic, both-direction close of existing
streams while preserving conntrack/egress, IPv6/spoof blocking, quarantine,
and offline cleanup. It does not boot a microVM or validate a real TAP deployment.
The packet test skipped in this workspace because namespace creation was
denied (`Operation not permitted`). Document that permission limitation, not
@@ -1011,7 +1031,7 @@ on an isolated Linux host:
| Firecracker exits early | VM `firecracker.log`, VM config, `/dev/kvm` access |
| VM is `dead` in `list` | PID/start token in state, `/proc/<pid>`, VM log |
| Cannot stop legacy VM | Missing start/boot identity or failed protected binary/socket match; never guess a PID |
| Guest has no egress | `ip route show default`, bridge address, TAP state, iptables rules |
| Guest has no egress | Host connectivity/routes, bridge/TAP state, `uvm-egress` iptables rules; `start` refreshes networking on a running VM |
| Policy missing/drift/unknown | Actual nft JSON and ownership, STP/group mask, permissions; explicit sync after fixing cause |
| Retained-disk start fails | `disk_ready`, safe private path, kernel/VMM integrity, process identity, retained network, pending operation |
| API server refuses to start | `UVM_API_TOKEN`, requested host, TLS cert/key files |
@@ -1035,9 +1055,9 @@ The code is intentionally honest about current limits:
- Guest health is inferred from VMM process state, not application readiness.
- No quotas, DHCP, host-port mapping, UDP/IPv6 services, or network tenancy.
- No guest snapshots, extra disks, production image builder, or SSH-key injection.
- Per-VM private TCP ingress policy exists, but public connectivity, DNS,
- Per-VM private TCP ingress policy exists, but public inbound connectivity, DNS publication,
guest reverse proxy/TLS, and external firewall integration remain out of scope.
- Existing egress `iptables` rules are incremental and unchanged; only the
- Shared egress `iptables` rules are incremental and idempotent; only the
private bridge policy is atomically rendered per VM.
- No autostart, background reconciliation, or guest-coordinated shutdown.
- The JSON inventory is suitable for one host, not distributed coordination.