Documentation
¶
Index ¶
- Constants
- func WarnIfLegacyIptables(backend string, logger *slog.Logger)
- type Manager
- func (m *Manager) ApplyEgressPolicy(containerIP string, allowCIDRs, denyCIDRs []string) error
- func (m *Manager) BlockAllEgress(containerIP string) error
- func (m *Manager) BlockAllIngress(containerIP string) error
- func (m *Manager) ClearBlockAllEgress(containerIP string) error
- func (m *Manager) ClearBlockAllIngress(containerIP string) error
- func (m *Manager) ClearEgressPolicy(containerIP string, allowCIDRs, denyCIDRs []string) error
- func (m *Manager) Enabled() bool
- func (m *Manager) EnsureChain() error
- func (m *Manager) ReassertChain() error
- func (m *Manager) ResetChainLatch()
- func (m *Manager) SetBridgeSubnet(subnet string)
- type RuleBackend
Constants ¶
const ( BackendExec = "exec" BackendNetlink = "netlink" ChainDockerUser = "DOCKER-USER" ChainAerolvmUser = "AEROLVM-USER" )
Backend names for SB_NETRULES_BACKEND.
Variables ¶
This section is empty.
Functions ¶
func WarnIfLegacyIptables ¶ added in v0.6.0
WarnIfLegacyIptables logs a boot-time warning when the netlink backend is selected on a host whose iptables binary runs in legacy (xtables) mode. The netlink backend writes to the nft tables, which legacy iptables cannot see — the kernel evaluates BOTH rule sets, so flipping SB_NETRULES_BACKEND with live sandboxes strands the previous backend's ACCEPT/DROP rules on recycled container IPs (TODOS.md "netrules backend switch on iptables-legacy hosts"). Best-effort: a missing binary or exec failure stays silent — no signal is not a legacy host.
Types ¶
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
func NewWithBackend ¶ added in v0.5.5
func NewWithBackend(backend RuleBackend) *Manager
NewWithBackend builds an enabled Manager over an injected backend. Test seam only — production wiring goes through New.
func NewWithOptions ¶ added in v0.6.0
NewWithOptions builds a Manager with the chosen RuleBackend. userChain selects the filter chain for per-IP rules; empty defaults to DOCKER-USER. Unknown backend names fall back to exec with an error so misconfig is loud.
func (*Manager) ApplyEgressPolicy ¶ added in v0.5.4
ApplyEgressPolicy installs a per-container selective egress policy in DOCKER-USER, scoped by source IP and comment-tagged (see egressPolicyComment). Exactly one mode is expected (callers validate mutual exclusivity):
- allowCIDRs non-empty → allowlist: ACCEPT each CIDR, DROP everything else.
- denyCIDRs non-empty → blocklist: DROP each CIDR, leave the rest to Docker's default ACCEPT.
Re-apply is idempotent: every rule is Exists-checked before Insert, so the start/reconcile reapply paths can call this repeatedly without duplicating.
func (*Manager) BlockAllEgress ¶
BlockAllEgress installs a DROP rule for traffic originating from containerIP. The rule lives in DOCKER-USER, the chain Docker explicitly reserves for operator-defined firewall rules. DOCKER-USER is jumped from FORWARD *before* DOCKER-FORWARD, so our DROP fires before Docker's blanket "iifname docker0 accept" rule that would otherwise short-circuit any rule appended directly to FORWARD. This works on iptables-legacy and on Docker 28+/iptables-nft (which writes through to nftables) alike.
func (*Manager) BlockAllIngress ¶ added in v0.1.7
BlockAllIngress installs a DROP rule for traffic destined for containerIP, the mirror of BlockAllEgress on the destination axis. Used by the network quota enforcer when net_bytes_in_limit is crossed. The honest caveat (also documented in plans/network-usage-tracking.md): host-side ingress is counted after the NIC has accepted the packet, so the meter is "what the container would have seen" rather than "bytes spent on the wire." Same chain (DOCKER-USER) and idempotency check pattern as the egress mirror.
func (*Manager) ClearBlockAllEgress ¶
func (*Manager) ClearBlockAllIngress ¶ added in v0.1.7
func (*Manager) ClearEgressPolicy ¶ added in v0.5.4
ClearEgressPolicy removes the rules ApplyEgressPolicy would have installed for the same (containerIP, allowCIDRs, denyCIDRs). The caller passes the policy persisted on the sandbox row so cleanup is exact and comment-scoped — the blanket BlockAllEgress DROP (no comment) is left untouched.
func (*Manager) EnsureChain ¶ added in v0.7.1
EnsureChain bootstraps the filter user chain and its FORWARD jump once per Manager lifetime. Idempotent and latched like EnsureLayer4Ready: concurrent callers single-flight through chainMu; success sets chainReady.
func (*Manager) ReassertChain ¶ added in v0.7.2
ReassertChain re-runs the chain + FORWARD-jump bootstrap WITHOUT the latch, so a caller (e.g. the containerd netns reconcile ticker) can re-assert the jump after a dockerd restart flushes/reorders FORWARD and drops it. Both steps are idempotent; a no-op when disabled or the backend cannot bootstrap.
func (*Manager) ResetChainLatch ¶ added in v0.7.1
func (m *Manager) ResetChainLatch()
ResetChainLatch clears the bootstrap latch. Test-only seam.
func (*Manager) SetBridgeSubnet ¶ added in v0.7.5
SetBridgeSubnet records the sandbox bridge subnet whose forwarded traffic EnsureChain/ReassertChain must ACCEPT (below any per-IP DROP). Empty = no-op.
type RuleBackend ¶ added in v0.5.5
type RuleBackend interface {
Exists(table, chain string, rulespec ...string) (bool, error)
Insert(table, chain string, pos int, rulespec ...string) error
Delete(table, chain string, rulespec ...string) error
}
RuleBackend is the subset of iptables operations the Manager drives. Production always wraps *go-iptables' IPTables; tests substitute an in-memory backend so rule-state semantics (which rules survive an adopt, a clear, a reapply) are assertable without root or a linux host.
func NewNetlinkBackend ¶ added in v0.6.0
func NewNetlinkBackend() (RuleBackend, error)
NewNetlinkBackend wires the per-operation nftables connection factory. Callers must be on linux; non-linux builds use the stub that always errors.