Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
d0705a0
[LXC] Scrub and apply proxy env vars through the shared helper
dhoehna Aug 8, 2026
b74f5bf
Correct the LXC client note: the integration is planned, not wired
dhoehna Aug 8, 2026
40514a6
[LXC] Pin the proxy hostname instead of rewriting the URL host
dhoehna Aug 9, 2026
764900b
Drop a dead bracket guard and document why unbracketing is load-bearing
dhoehna Aug 9, 2026
bf37b12
[LXC] Make an unpinnable proxy address unrepresentable
dhoehna Aug 9, 2026
445ea2e
[LXC] Update proxy address spec for the unpinnable-address fix
dhoehna Aug 9, 2026
91b3760
[LXC] Fail closed when firewall rules cannot be scoped to the container
dhoehna Aug 9, 2026
a3d82c0
[LXC] Spec the fail-closed contract for unscopeable firewall rules
dhoehna Aug 9, 2026
47e00a9
[LXC] Hook the firewall chain onto the bridge port so it actually fil…
dhoehna Aug 9, 2026
3a05f6a
[LXC] Spec the FORWARD hook contract and assert enforcement end to end
dhoehna Aug 9, 2026
792d1ae
[LXC] Make deny rules win over allow rules and fail closed on an unre…
dhoehna Aug 9, 2026
988b609
[LXC] Spec deny precedence and assert an overlapping allow cannot def…
dhoehna Aug 9, 2026
8595d5d
[LXC] Correct the network policy docs and make the E2E suite gate in CI
dhoehna Aug 9, 2026
4ed9d4d
[LXC] Set FORWARD to ACCEPT in CI so only MXC rules can block
dhoehna Aug 9, 2026
76eb242
Keep Bubblewrap startable when no veth exists to scope the chain to
dhoehna Aug 9, 2026
3dd4196
Cover the Bubblewrap veth declaration so deleting it fails a test
dhoehna Aug 9, 2026
c098239
Pin the negative case of the missing-veth accessor
dhoehna Aug 9, 2026
76c4c51
[LXC] Admit network.proxy for LXC and reject the forms it cannot reach
dhoehna Aug 10, 2026
d1da5d3
[LXC] Let a caller force lxc-attach to clear the inherited environment
dhoehna Aug 10, 2026
de6c96a
[LXC] Wire the proxy-env scrub into the production execution path
dhoehna Aug 10, 2026
8c6fa72
[LXC] Restrict egress to the proxy endpoint when one is configured
dhoehna Aug 10, 2026
a46ad0a
[LXC] Pin the proxy host inside the container before running the script
dhoehna Aug 10, 2026
8dd810d
[LXC] Add the deny-all-except-proxy integration test
dhoehna Aug 10, 2026
63974b7
[LXC] Document the cooperative-proxy posture
dhoehna Aug 10, 2026
f397020
[LXC] Scope the integration test's DNS claims to what FORWARD can see
dhoehna Aug 10, 2026
daac8ab
[LXC] Require a firewall enforcement mode for network.proxy
dhoehna Aug 10, 2026
cfd062c
[LXC] Fail closed when an allow rule can outrank an unresolvable deny
dhoehna Aug 10, 2026
aafb0de
[LXC] Claim FORWARD hooks before installing them, not after
dhoehna Aug 10, 2026
19ac107
[LXC] Clear a stale proxy host pin when a run pins nothing
dhoehna Aug 10, 2026
edb9d38
Merge remote-tracking branch 'origin/main' into user/dahoehna/lxc-net…
dhoehna Aug 10, 2026
c3d133f
[LXC] Derive the chain name in the specs instead of hard-coding it
dhoehna Aug 10, 2026
c7c6142
[LXC] Narrow the deny-precedence failure to a catch-all allow
dhoehna Aug 10, 2026
130b1c9
[LXC] Reject proxy URLs that carry credentials
dhoehna Aug 10, 2026
3de0f5b
[LXC] Stop staging /etc/hosts through a predictable /tmp file
dhoehna Aug 10, 2026
c00f941
[LXC] Fail closed on a proxy the enforcement mode will not enforce
dhoehna Aug 10, 2026
8e1cf62
[LXC] Carry the reply path for allowed outbound connections
dhoehna Aug 10, 2026
739d23f
[LXC] Run the E2E suite under the forward policy production has
dhoehna Aug 10, 2026
d983827
Revert "[LXC] Run the E2E suite under the forward policy production has"
dhoehna Aug 10, 2026
d93bf12
[LXC] Enforce the no-credential proxy invariant at the runner boundary
dhoehna Aug 10, 2026
221f8d1
[LXC] Redact the proxy URL in the diagnostics that run before the guard
dhoehna Aug 10, 2026
628b0b4
Treat an unreadable sysfs as bridged instead of as directly routed
dhoehna Aug 10, 2026
12eb8e9
Do not read a dangling interface symlink as directly routed
dhoehna Aug 10, 2026
97ff4b1
Pin the metadata asymmetry with dangling-symlink tests
dhoehna Aug 10, 2026
b657fc7
Find proxy credentials in an opaque URL, not just an authority one
dhoehna Aug 11, 2026
dad5aeb
Stop rewriting /etc/hosts when the read that feeds it failed
dhoehna Aug 11, 2026
9595b58
Cover the credentialed-proxy rejection from outside the process
dhoehna Aug 11, 2026
bfcbc82
Close three holes an independent review found in the credential guard
dhoehna Aug 11, 2026
7a9948b
Stop reading a port separator as a URL scheme
dhoehna Aug 11, 2026
b67f7ec
Refuse to rewrite /etc/hosts through a symbolic link
dhoehna Aug 11, 2026
d26d826
Stop the credential test from publishing the secret it guards
dhoehna Aug 11, 2026
6392ea0
[LXC] Stop leading whitespace from hiding a proxy credential
dhoehna Aug 11, 2026
5c057c6
[LXC] Stop the drift guard from printing the credentials it guards
dhoehna Aug 11, 2026
aef66b5
[LXC] Stop a backslash from hiding a proxy credential, and pin the gu…
dhoehna Aug 11, 2026
6309789
[LXC] Correct the return-path rule's safety claim with a measurement
dhoehna Aug 11, 2026
a4613e3
Judge a proxy URL by what can leak, not only by what a parser sees
dhoehna Aug 11, 2026
82e8b0e
Fix two E2E scripts that asserted on chain names that can never exist
dhoehna Aug 11, 2026
cdc8cf6
Describe what the code does in comments, not how it got there
dhoehna Aug 11, 2026
0184689
Say what the data is, not how the code uses it
dhoehna Aug 11, 2026
a7ccd08
Say why the test is `!= DirectlyRouted`
dhoehna Aug 11, 2026
dba2f73
Put in doc comments what the code cannot say
dhoehna Aug 12, 2026
19be524
Correct two claims review showed were false
dhoehna Aug 12, 2026
0c93721
Fix hook ownership stranding, empty failure reasons, and add live pro…
dhoehna Aug 12, 2026
967f798
Add end-to-end coverage for pin lifetime, preserved policy, and the b…
dhoehna Aug 13, 2026
6ce453b
Stop clobbering caller proxy settings, and widen two guards past LXC
dhoehna Aug 13, 2026
c80ae1e
Refuse blockedHosts under a proxy, and pin only what the run pinned
dhoehna Aug 13, 2026
069194d
Write the two address families once, and bound the proxy answer
dhoehna Aug 13, 2026
e8bd2c7
Give the network scripts one chain-name helper
dhoehna Aug 13, 2026
ab5202b
Format three files rustfmt was rejecting
dhoehna Aug 14, 2026
a35fed0
Remove a return rule whose insert reported failure
dhoehna Aug 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions .github/workflows/lxc-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
name: LXC E2E Tests

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read

jobs:
lxc-e2e:
name: LXC-Exec Container and Network Policy
runs-on: ubuntu-latest
timeout-minutes: 45

steps:
- uses: actions/checkout@v6

- name: Setup Rust toolchain
run: rustup update stable

- name: Point cargo at the MxcDependencies feed
uses: ./.github/actions/setup-cargo-feed

- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: src

- name: Install LXC and firewall tooling
run: |
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y \
lxc lxc-templates lxc-utils iptables debootstrap uidmap bridge-utils

# A bridged veth only reaches the FORWARD chain while br_netfilter is
# delivering bridged packets to iptables. Without it the firewall rules
# install cleanly and never fire, so the network policy tests would pass
# against a firewall that filters nothing.
- name: Enable bridge netfilter
run: |
sudo modprobe br_netfilter
sudo sysctl -w net.bridge.bridge-nf-call-iptables=1
sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=1

# GitHub-hosted runners ship Docker, and Docker sets the IPv4 FORWARD
# policy to DROP. That breaks these tests twice over.
#
# First, it breaks them outright. MXC hooks its chain on traffic leaving
# the container (`-i <veth>` / `--physdev-in <veth>`), so an allowed
# request is accepted on the way out -- but the reply arrives in the
# opposite direction, matches no MXC rule, falls through to the policy,
# and is dropped. The connection times out and an explicitly allowed
# destination looks unreachable. Observed exactly that: DNS resolved,
# because dnsmasq on lxcbr0 is host-local and never traverses FORWARD,
# and then `wget: can't connect to remote host (140.82.116.5)`.
#
# Second, and worse, it would make the deny cases meaningless. Under a
# DROP policy a container with NO working MXC hook at all is also
# unreachable, so the enforcement and deny-precedence tests would report
# success against a firewall that filters nothing -- which is the precise
# bug this suite exists to detect, and the reason these tests carry
# positive controls.
#
# Setting the policy to ACCEPT restores the condition the tests were
# written for: the host forwards by default, so the ONLY thing that can
# block container traffic is a rule MXC installed. A missing hook then
# shows up as an unexpected success and fails the deny case loudly.
# A narrower conntrack RELATED,ESTABLISHED rule is not an alternative
# here. The chain already carries return rules in both the interface and
# the physdev form, and both were measured inert on this bridged
# topology: a reply is routed toward lxcbr0, so the bridge port is not
# selected when FORWARD runs and neither form matches. Scoping the return
# direction by the container's address is the fix, and it is deferred --
# it needs the address plumbed through to the manager and a live bridged
# measurement, not another untested rule.
- name: Let the host forward, so only MXC rules can block
run: |
sudo iptables -P FORWARD ACCEPT
sudo ip6tables -P FORWARD ACCEPT
sudo iptables -S FORWARD | head -5

- name: Report the environment these tests depend on
run: |
echo "--- kernel ---"
uname -a
echo "--- lxc ---"
lxc-create --version || echo "MISSING lxc-create"
echo "--- iptables ---"
sudo iptables --version || echo "MISSING iptables"
sudo ip6tables --version || echo "MISSING ip6tables"
echo "--- forward policy (must be ACCEPT, or deny cases pass vacuously) ---"
sudo iptables -S FORWARD | head -1
sudo ip6tables -S FORWARD | head -1
echo "--- bridge netfilter ---"
cat /proc/sys/net/bridge/bridge-nf-call-iptables || echo "MISSING bridge-nf-call-iptables"
cat /proc/sys/net/bridge/bridge-nf-call-ip6tables || echo "MISSING bridge-nf-call-ip6tables"
echo "--- host ipv6 ---"
cat /proc/net/if_inet6 || echo "no /proc/net/if_inet6 (IPv6 disabled)"

- name: Build lxc-exec
working-directory: src
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: cargo build --release -p lxc --bin lxc-exec

# MXC_LXC_TESTS_REQUIRE_EXECUTION turns an honest skip into a failure.
# On a developer box a missing ip6tables is a reason to run what you can.
# Here the runner is provisioned specifically to execute this suite, so a
# skip means a prerequisite disappeared and the gate would go green while
# testing nothing.
- name: Run LXC E2E suite
env:
MXC_LXC_TESTS_REQUIRE_EXECUTION: "1"
run: sudo --preserve-env=MXC_LXC_TESTS_REQUIRE_EXECUTION bash tests/scripts/run_lxc_all_tests.sh

- name: Show leftover firewall state on failure
if: failure()
run: |
echo "--- FORWARD chain ---"
sudo iptables -S FORWARD || true
sudo ip6tables -S FORWARD || true
echo "--- MXC chains ---"
sudo iptables -S | grep -E '^-N MXC-' || echo "none"
sudo ip6tables -S | grep -E '^-N MXC-' || echo "none"

- name: Upload logs on failure
if: failure() || cancelled()
uses: actions/upload-artifact@v6
with:
name: lxc-e2e-logs-${{ github.event.pull_request.number || github.run_number }}
retention-days: 7
path: |
logs/
**/*.log
151 changes: 147 additions & 4 deletions docs/lxc-support/lxc-backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,65 @@ Filesystem policies are enforced via bind mounts in the container configuration:

## Network Policy

Everything in this section requires `enforcementMode` to be `firewall` or `both`. Under the default `capabilities` mode, MXC installs no iptables rules at all, so `defaultPolicy`, `allowedHosts`, and `blockedHosts` are parsed but never take effect.

Network policies are enforced with parallel `iptables` and `ip6tables` chains scoped to the container's virtual ethernet (veth) interface:

| Policy | Implementation |
|--------|---------------|
| `defaultPolicy: "block"` | Final DROP rule in the container chain |
| `defaultPolicy: "allow"` | Final ACCEPT rule in the container chain |
| `allowedHosts` | ACCEPT rules for IP literals, CIDR blocks, or resolved hostnames |
| `blockedHosts` | DROP rules for IP literals, CIDR blocks, or resolved hostnames |

`allowedHosts` and `blockedHosts` entries may be bare IPv4/IPv6 literals, IPv4/IPv6 CIDR blocks, or hostnames. Hostnames are resolved to both A and AAAA records; IPv4 destinations are applied to the `iptables` chain and IPv6 destinations are applied to the `ip6tables` chain. Entries whose CIDR prefix is out of range for its family (or otherwise malformed) are reported as unresolved and skipped, leaving the rest of the policy in force. Host-list rules match all ports and protocols; port- and protocol-specific egress rules are not supported.
| `blockedHosts` | DROP rules for IP literals, CIDR blocks, or resolved hostnames, emitted *before* the ACCEPT rules |
Comment thread
dhoehna marked this conversation as resolved.

**A deny wins over an overlapping allow.** `iptables` evaluates a chain top to
bottom and stops at the first match, so precedence is decided purely by
emission order. All `blockedHosts` rules are emitted ahead of all
`allowedHosts` rules, which means a destination named by both lists is dropped.
Without that ordering an allow entry broad enough to cover a blocked
destination — `0.0.0.0/0`, or a CIDR containing the blocked address — silently
defeats the block, and the resulting chain looks fully populated while
filtering nothing.

Three limits on that guarantee are worth stating plainly, because "deny always
wins" is not true without them:

- **An already-established flow is exempt.** The base chain accepts
`ESTABLISHED,RELATED` unconditionally and is installed ahead of the generated
policy rules. A flow that conntrack already knows keeps matching that rule
rather than its `blockedHosts` DROP, so the guarantee covers flows opened
after the chain exists — not one opened during the window between container
start and rule application, nor one surviving in the host's conntrack table
from an earlier run of a container with the same name.
- **DNS is exempt.** The base chain accepts UDP and TCP destination port 53
unconditionally and is installed ahead of the generated policy rules, so
port-53 traffic to a blocked destination is accepted before its DROP rule is
reached. Narrowing that rule needs to know which resolver addresses are
legitimate, and no schema field carries them today.
- **A hostname in both lists is resolved twice.** Each list entry is resolved
independently, so a name behind round-robin DNS can return one address for
the `blockedHosts` entry and a different one for the `allowedHosts` entry.
The guarantee holds for *addresses*, not for names. Use literal IPs or CIDRs
when a destination must be denied deterministically.

`allowedHosts` and `blockedHosts` entries may be bare IPv4/IPv6 literals, IPv4/IPv6 CIDR blocks, or hostnames. Hostnames are resolved to both A and AAAA records; IPv4 destinations are applied to the `iptables` chain and IPv6 destinations are applied to the `ip6tables` chain. Host-list rules match all ports and protocols; port- and protocol-specific egress rules are not supported.

An entry that resolves to nothing — an unknown hostname, or a CIDR prefix out
of range for its family — cannot be turned into a rule. What that costs
depends on the entry and on `defaultPolicy`:

| Entry | `defaultPolicy` | Behavior |
|-------|-----------------|----------|
| `allowedHosts` | either | Reported as unresolved and skipped. Failing to write an ACCEPT rule can only make the policy more restrictive |
| `blockedHosts` | `block` | Reported as unresolved and skipped. The closing DROP already denies the destination, so the unwritten rule was redundant |
| `blockedHosts` | `allow` | **Fails firewall setup.** The chain ends in ACCEPT, so the unwritten DROP was the only thing that would have denied that destination, and skipping it silently converts a deny into an allow |

One gap remains open and is not detected: under `defaultPolicy: "block"`, an
`allowedHosts` entry broad enough to cover a destination whose `blockedHosts`
rule went unwritten still reaches that destination. Detecting it would require
the address the failed entry was *meant* to resolve to, which is by definition
unavailable, so no check over the policy text can be complete — and a partial
check would imply a guarantee this code cannot make.

Before programming the IPv6 chain, MXC probes `ip6tables` with a read-only `ip6tables -S` and classifies the result three ways:

Expand All @@ -130,10 +179,104 @@ Before programming the IPv6 chain, MXC probes `ip6tables` with a read-only `ip6t

Host IPv6 activity is read from `/proc/net/if_inet6`: a non-loopback interface with an IPv6 address counts as active, while loopback-only `::1` on `lo` (present even on IPv4-only hosts) does not. If that file cannot be read at all — as opposed to being absent, which means IPv6 is disabled — the state is treated as *unknown* rather than as a confirmed "IPv6 is off", so an unreadable IPv6 state fails closed instead of leaving IPv6 unfiltered.

The chains are hooked into `FORWARD` for container egress by matching the host-side veth as the input interface. If MXC cannot discover the container veth, it skips the `FORWARD` hook with a warning rather than applying host-wide rules.
The chains are hooked into `FORWARD` for container egress with **up to two
rules per family**, because the input interface `FORWARD` sees depends on how
the veth is attached:

| Attachment | Rule that matches |
|------------|-------------------|
| veth routed directly by the host | `-i <veth>` |
| veth enslaved to a bridge (the default LXC topology) | `-m physdev --physdev-in <veth>` |

The two are mutually exclusive for any given packet, so nothing is counted
twice. Installing only `-i <veth>` is what previously let a fully populated
deny-all chain sit in the ruleset filtering nothing on the default bridged
topology.

The `physdev` rule is required only on a bridged veth. On a directly routed
veth a host whose kernel lacks the `physdev` match logs a warning and
continues with the interface rule alone, which is the rule that matches there;
on a bridged veth the same failure is fatal, because `physdev` is the only
rule that could ever match.

A bridged veth additionally requires `br_netfilter` to be delivering bridged
packets to iptables. With `/proc/sys/net/bridge/bridge-nf-call-iptables` absent
or `0`, both hook rules install cleanly and neither ever fires. MXC reads that
file and **fails firewall setup** rather than reporting success for a chain
that could never be reached. When the IPv6 chain is programmed,
`/proc/sys/net/bridge/bridge-nf-call-ip6tables` is checked separately and to
the same standard.

If MXC cannot discover the container veth at all, firewall setup **fails** and
the partially created chains are rolled back. An unhooked chain is never
traversed, so reporting success would hand the caller a deny-all chain that
filters nothing — strictly worse than no firewall, because it looks enforced.
Installing the rules host-wide instead is not an option either: unscoped, they
would apply to every container and to the host's own traffic.

Firewall state is torn down automatically with best-effort removal of the `FORWARD` hooks and both per-container chains; there is no network-policy opt-out field. Setup failures after partial creation are rolled back before returning an error, so retries do not trip over leftover chains.

### Cooperative proxy

`network.proxy` puts the container in a "deny all except the proxy" posture:
egress is restricted to the proxy endpoint, and `HTTP_PROXY`/`HTTPS_PROXY` are
injected so a cooperating client uses it. The env vars are the routing hint;
the firewall is the enforcement, so an application that ignores them cannot
reach the internet directly.

The chain is hooked into `FORWARD`, so what it governs is traffic the host
*routes* on the container's behalf. Traffic addressed to the bridge gateway
itself — where LXC's `dnsmasq` listens, and where a host-local proxy would run
— is delivered locally and traverses `INPUT`, which this chain does not hook.
Closing that path needs an INPUT hook and is tracked separately, so "reaches
nothing" is accurate for forwarded egress and not for host-local destinations.

Only the `{ "url": "http://proxy.example:8080" }` form is accepted. The LXC
container has its own network namespace, so `{ "localhost": <port> }` names the
*container's* loopback rather than the host's — the injected proxy would be
unreachable and the firewall rule would never match. `{ "builtinTestServer":
true }` is rejected for the same reason, as is a `url` whose host is a loopback
literal.

Two further constraints are enforced at parse time, both rejections rather than
silent corrections:

- **`enforcementMode` must be `firewall` or `both`.** Under the default
`capabilities` mode no iptables rules are installed, so the proxy env vars
would be injected while direct egress stayed open — a config that reads as
deny-all-except-proxy and enforces neither half. MXC refuses it rather than
auto-promoting the mode, so a stated enforcement level is never silently
rewritten.
- **The `url` must not carry credentials.** LXC passes the proxy URL to
`lxc-attach` as a `--set-var` argument, and process arguments are
world-readable through `/proc/<pid>/cmdline`, so inline `user:pass@` would be
visible to every local user for the lifetime of the command. Supply the
credentials to the proxy itself instead.

The chain a proxied container gets differs from the ordinary one in four ways,
each of which would otherwise be a hole in the posture:

| Ordinary chain | Proxied chain | Why |
|----------------|---------------|-----|
| Terminal rule follows `defaultPolicy` | Terminal rule is always DROP | An ACCEPT terminal would make the proxy rule above it meaningless |
| Accepts UDP/TCP port 53 | No DNS rule | An unscoped port-53 accept is a standing DNS-tunnel exfil path through a deny-all posture |
| Accepts `-i lo` and `ESTABLISHED,RELATED` | Neither | Neither describes traffic this chain sees, and the conntrack rule would carry flows the proxy never brokered |
| Programs `allowedHosts` and `blockedHosts` | Programs neither | A block entry is redundant under the closing DROP, and an allow entry naming anything but the proxy contradicts the model |

The IPv6 chain of a proxied container carries its closing DROP and nothing
else, because the proxy rule is emitted with IPv4 `iptables` only. An IPv6
proxy endpoint is therefore rejected outright rather than silently discarded.

With DNS closed, a container handed a proxy URL naming a hostname has no
resolver to find it with. MXC resolves the proxy once, when it builds the
firewall rule, and writes that same mapping into the container's `/etc/hosts`
before the script runs — so the name resolves, and it resolves to an address
the chain allows. The URL itself is left alone: rewriting its host to an IP
literal would break SNI and certificate validation for an `https://` proxy.
Every address the proxy host resolved to is opened, since they all belong to
that same proxy. If the hosts entry cannot be written, execution **fails**
rather than running a container whose proxy is unreachable.

## Usage

### Command Line
Expand Down
13 changes: 10 additions & 3 deletions docs/schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,16 @@ production configs and the dev schema when working on experimental features:
"proxy": { "localhost": 8080 } // Loopback proxy port (processcontainer; bubblewrap; seatbelt)
// (use { "builtinTestServer": true } for the bundled
// testing-only proxy; requires --allow-testing-features)
// WSLC supports the cooperative proxy too, but only via
// { "url": "http://proxy.example:8080" } (own-netns:
// localhost/builtinTestServer are unreachable, rejected)
// WSLC and LXC support the cooperative proxy too, but
// only via { "url": "http://proxy.example:8080" }
// (own-netns: localhost/builtinTestServer are
// unreachable, rejected)
// Under LXC the proxy is enforced: forwarded egress is
// restricted to the proxy endpoint and nothing else, so
// the allow/block host lists and DNS are not opened.
// The chain hooks FORWARD, so traffic addressed to the
// bridge gateway itself is delivered locally via INPUT
// and is outside what this chain governs.
},

"ui": {
Expand Down
Loading