Skip to content

[Bubblewrap/LXC] Address common network policy gaps - model 1#631

Open
dhoehna wants to merge 1 commit into
microsoft:mainfrom
dhoehna:user/dahoehna/lxc-net-model1-ipv6-cidr-port-proto
Open

[Bubblewrap/LXC] Address common network policy gaps - model 1#631
dhoehna wants to merge 1 commit into
microsoft:mainfrom
dhoehna:user/dahoehna/lxc-net-model1-ipv6-cidr-port-proto

Conversation

@dhoehna

@dhoehna dhoehna commented Jul 10, 2026

Copy link
Copy Markdown

Linked work item: AB#62830559 — [Bubblewrap/LXC] Address common network policy gaps - model 1

Summary

Adds IPv6, CIDR, port, and protocol filtering to the LXC iptables enforcement path.

  • resolve_host now returns dual-stack (IPv4 + IPv6); IPv6 literals / AAAA results are retained instead of dropped.
  • New run_ip6tables helper + a parallel v6 chain mirroring loopback / ESTABLISHED,RELATED / DNS / default-policy, with an ip6tables -I FORWARD hook and matching cleanup.
  • CIDR passthrough for v4 and v6 (validated via std::net), routed to the correct table by address family.
  • Per-rule port (--dport) and protocol (-p tcp/udp/icmp) enforcement via a new internal egress_rules model field; the legacy allowed_hosts / blocked_hosts path is preserved.
  • Rule construction refactored into pure helpers returning arg vectors, with unit tests; the old IPv6-drop tests and the resolve_host doc comment were updated to the new dual-stack behavior.

Model

  • Adds ContainerPolicy.egress_rules: Vec<EgressRule> (+ EgressRule, Protocol, RuleAction), default empty.

Validation

  • cargo fmt --all -- --check; cargo clippy --target x86_64-unknown-linux-gnu -p lxc_common -D warnings — clean
  • cargo test -p wxc_common — 395 passed
  • cargo check --target x86_64-unknown-linux-gnu -p lxc_common --tests — pass

Coupling

EgressRule / Protocol / RuleAction are also introduced independently by the schema PR (AB#62830582) and net-model-2 (AB#62830341); merge-time reconciliation is expected. The JSON parser for egress_rules is intentionally owned by the schema PR.

Microsoft Reviewers: Open in CodeFlow

…(AB#62830559)

- resolve_host returns dual-stack; add ip6tables v6 chain mirroring the v4 chain.
- CIDR (v4/v6) passthrough; per-rule --dport and -p tcp/udp/icmp via new EgressRule model field.
- Pure rule-builder helpers with unit tests; update legacy IPv6-drop tests to dual-stack.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3b78bec0-e139-4cfd-9c10-092ef986d4f4
Copilot AI review requested due to automatic review settings July 10, 2026 22:56
@dhoehna dhoehna requested a review from a team as a code owner July 10, 2026 22:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the LXC firewall enforcement path to support a richer, dual-stack egress network policy model (IPv4 + IPv6), including CIDR destinations and per-rule protocol/port filtering, while preserving the legacy allowed/blocked host lists.

Changes:

  • Added ContainerPolicy.egress_rules with supporting EgressRule, Protocol, and RuleAction types in wxc_common.
  • Updated the LXC iptables enforcement implementation to build parallel iptables + ip6tables chains and to preserve IPv6 literals/AAAA resolution results.
  • Refactored rule construction into helper functions returning argument vectors, with unit tests for the new rule-building behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
src/core/wxc_common/src/models.rs Introduces the egress_rules policy model and supporting enums/structs on ContainerPolicy.
src/backends/lxc/common/src/network_iptables.rs Implements dual-stack (iptables/ip6tables) rule application, CIDR/protocol/port handling, and adds unit tests for rule argument construction.

Comment on lines +120 to +124
/// Bare IPv4/IPv6 literals are retained in their matching family. CIDR
/// strings are accepted after validating the network address and prefix
/// length, then passed through unchanged. Hostnames are resolved to both A
/// and AAAA records so IPv4 destinations route to `iptables` and IPv6
/// destinations route to `ip6tables`.
Comment on lines +188 to +194
fn protocol_arg(protocol: &Protocol) -> &'static str {
match protocol {
Protocol::Tcp => "tcp",
Protocol::Udp => "udp",
Protocol::Icmp => "icmp",
}
}
Comment on lines +291 to +299
for protocol in &protocol_options {
for port in &port_options {
let rule = Self::build_single_rule_args(
chain_name,
destination,
action,
protocol.as_ref(),
*port,
);
Comment on lines 482 to +489
Self::run_iptables(
&["-I", "FORWARD", "-o", iface, "-j", &self.chain_name],
logger,
)?;
Self::run_ip6tables(
&["-I", "FORWARD", "-o", iface, "-j", &self.chain_name],
logger,
)?;
// Remove from FORWARD (only if we had a veth interface and hooked it)
if let Some(ref iface) = self.veth_interface {
let _ = Self::run_iptables(
&["-D", "FORWARD", "-o", iface, "-j", &self.chain_name],
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants