log the agent bridge's forwarded flows in the hive_egress table
A forward chain in the hive-owned nft table logs each new flow from the agent bridge to the uplink (v4 and v6) and counts every packet. It never blocks. The mesh interface is skipped. Logging is rate limited per source address; a flow that limit cannot log gets one line from a shared limit with its own prefix. services.hyperhive.network.egress.forward selects accept, log (default) or drop; drop is refused at evaluation until the interception it needs exists.
This commit is contained in:
parent
f5e7caa2eb
commit
bd79b58e78
1 changed files with 321 additions and 8 deletions
|
|
@ -231,7 +231,8 @@ only. An agent sends its outbound HTTP and HTTPS through it once its hive says
|
|||
the proxy is ready and it has fetched its proxy credential (see _Agents and the
|
||||
proxy_ below). Any other agent goes straight out through the NAT, as before,
|
||||
and so does any program that ignores the proxy variables: nothing blocks direct
|
||||
egress yet.
|
||||
egress yet. The host logs those direct connections (see _Agent bridge egress log_
|
||||
below).
|
||||
|
||||
Squid filters on the destination hostname: a `CONNECT` target or a plain-HTTP
|
||||
host. It never decrypts TLS, so it holds no signing key. It caches nothing.
|
||||
|
|
@ -517,6 +518,7 @@ the nix side sets up unconditionally:
|
|||
| IP forwarding | `boot.kernel.sysctl."net.ipv4.ip_forward" = 1` |
|
||||
| Internet NAT | `networking.nat { enable = true; internalInterfaces = [ bridgeName ]; }` — MASQUERADE on packets leaving via any external NIC |
|
||||
| Loopback DROP | `nix/host-modules/hive-egress.nix` — own nftables table `inet hive_egress` (whichever firewall the host runs): drops bridge → `127.0.0.0/8` and `::1` traffic; the kernel default `route_localnet=0` is the first layer |
|
||||
| Forward log | `nix/host-modules/hive-egress.nix` — the same table's `forward` chain logs and counts what the host routes from the bridge to the uplink; it blocks nothing (see _Agent bridge egress log_ below) |
|
||||
| Gateway access | `networking.firewall.interfaces.<bridge>.allowedTCPPorts = [ 80 443 ]` — lets isolated agents (private netns, veth on bridge) reach nginx on the host |
|
||||
| c0re signal | `HIVE_NETWORK_BRIDGE`, `HIVE_NETWORK_SUBNET` in `systemd.services.hive-c0re.environment` — both **required**; `hive-c0re` refuses to start without them |
|
||||
|
||||
|
|
@ -580,6 +582,52 @@ defence-in-depth against a compromised agent reaching the c0re dashboard HTTP at
|
|||
`127.0.0.1`). Agents have no legitimate reason to reach the dashboard over
|
||||
loopback — the hive-c0re admin socket is a UDS, not TCP.
|
||||
|
||||
### Agent bridge egress log
|
||||
|
||||
`services.hyperhive.network.egress.forward` sets what the `forward` chain of
|
||||
the `inet hive_egress` table does with traffic the host routes from the agent
|
||||
bridge to anywhere but the bridge and the `wg-hive` mesh interface. It takes
|
||||
`accept`, `log` (the default) or `drop`. The evaluation refuses `drop` for now:
|
||||
the interception that would carry an agent's web traffic through squid instead
|
||||
hasn't landed. In `log` mode the chain blocks nothing. It logs each new flow
|
||||
and counts every packet.
|
||||
|
||||
- **Which traffic.** IPv4 and IPv6 alike (the table is `inet`). The chain never
|
||||
sees traffic to the host's own addresses, because the host delivers it
|
||||
locally: a connection to squid on `<bridgeIp>:3128`, to dnsmasq or to the
|
||||
gateway leaves no line. Neither does anything squid or the host opens itself.
|
||||
- **The log line.** The kernel log carries one line per new flow, with the
|
||||
prefix `hive-egress-would-drop ` followed by the usual netfilter fields
|
||||
(`IN`, `OUT`, `SRC`, `DST`, `PROTO` and the ports). Read them with
|
||||
`journalctl -k -g hive-egress-would-drop`.
|
||||
- **Rate limit.** Each source address gets a burst of 20 lines, then one line a
|
||||
second, and the chain forgets it after a minute without a new flow. A flood
|
||||
from one agent can't hide another's flows, and it adds about 250 bytes of
|
||||
journal a second per source address at most. A flow the per-source limit
|
||||
can't log (the address is over its rate, or the table of addresses is full)
|
||||
gets one line with the prefix `hive-egress-would-drop-unmetered ` instead,
|
||||
from a limit shared by all addresses: 5 lines a second after a burst of 50,
|
||||
about 100 MB of journal a day at most. A flow never gets both lines. The
|
||||
counter in `nft list chain inet hive_egress forward` counts every packet,
|
||||
logged or not.
|
||||
- **Which agent.** `SRC` is the agent's address on the bridge. Containers get
|
||||
theirs from the hive's dnsmasq, which records each lease in
|
||||
`/var/lib/dnsmasq/dnsmasq.leases`, one line per lease:
|
||||
`<expiry> <mac> <ip> <hostname> <client-id>`. Look the `SRC` address up in the
|
||||
third column; the hostname names the container. A lease lasts one hour, so
|
||||
look an address up soon after the line appears.
|
||||
- **A hint, not evidence.** Until anti-spoofing lands, a container that forges
|
||||
its source address can mislead the log. It can file its flows under another
|
||||
agent's address, use up that agent's burst, or fill the table of addresses so
|
||||
that its own flows only reach the shared limit. It can also influence the
|
||||
lease behind the address. Use the log to find out what agents send directly
|
||||
now. Don't treat it as proof of which agent sent a flow, or as proof that a
|
||||
flow is absent. Anti-spoofing has to land before the log serves as the soak
|
||||
exit for enforcement.
|
||||
|
||||
Enforcement comes with later changes in the same series: the log only shows
|
||||
what such a change would cut.
|
||||
|
||||
## Cross-references
|
||||
|
||||
- `docs/4-implementation/networking/gateway.md` — vhost map + the gateway's other duties
|
||||
|
|
|
|||
Loading…
Reference in a new issue