childflow
childflow is a per-command-tree network sandbox for Linux. Run one command and its child processes in an isolated network context, control DNS / hosts / proxy behavior, apply outbound policy, capture only that tree's traffic, and emit structured flow logs for that tree.
About
childflow runs one command tree in an isolated network context and applies DNS, hosts, proxy, sandbox, policy, and capture controls only to that tree.
This is useful for tools that do not honor proxy environment variables consistently. childflow forces the proxy at the command tree's network path instead of relying on HTTP_PROXY, HTTPS_PROXY, or LD_PRELOAD-style interception.
It has two Linux backends: rootless-internal for the default day-to-day path, and rootful via --root when you need host-integrated behavior such as --iface or transparent interception.
- affects only the target command tree, not the whole host session
- can force DNS,
/etc/hosts, proxying, sandbox policy, packet capture, structured flow logging, and reusable profiles per command tree - can force proxying without depending on
HTTP_PROXY,HTTPS_PROXY, orLD_PRELOADtricks - can apply allow / deny CIDR policy and default-deny rules to outbound traffic
- defaults to
rootless-internal - uses
--rootonly for features like--ifaceand transparent interception
Examples
Install
cargo
Requirements
Host requirements:
- Linux only
ipiptablesip6tables
Additional rootless-internal requirements:
- user, network, and mount namespace support
/dev/net/tun- user namespaces enabled on the host
uidmapis recommended on Debian / Ubuntu style systems fornewuidmap/newgidmapfallback
Additional rootful requirements:
- root privileges
- writable
/proc/sys/net/ipv4/ip_forward - writable
/proc/sys/net/ipv6/conf/all/forwarding - Linux features required for TPROXY when proxy interception is used
If you are evaluating from macOS or another non-Linux environment, use the Docker workflows instead of trying to run the binary directly.
Usage
$ childflow --help
Run one command tree inside a controlled network sandbox
Usage: childflow [OPTIONS] [COMMAND]...
Arguments:
[COMMAND]... Command to execute
Options:
--profile <PROFILE>
Load effective defaults from a TOML profile file. Explicit CLI flags override the profile
--dump-profile
Print the effective profile as TOML and exit
-c, --capture <OUTPUT>
Write only the target command tree's traffic as pcapng
-C, --capture-point <OUTPUT_VIEW>
Select which capture point or view `--capture` should write. `child` is the current stable view [default: child] [possible values: child, egress, wire-egress, both]
--root
Use the rootful backend. Without this flag, childflow uses the default rootless backend
--doctor
Diagnose whether the current host is ready for the selected backend
-d, --dns <DNS>
Force DNS traffic for the child tree to this IPv4 or IPv6 resolver
--hosts-file <HOSTS_FILE>
Bind-mount an `/etc/hosts`-format file over the child's `/etc/hosts` so those entries are consulted first during name resolution
-p, --proxy <PROXY>
Configure an upstream proxy URI, for example http://127.0.0.1:8080, https://proxy.example.com:443, or socks5://host.docker.internal:10080. `--root` uses transparent interception, while the default rootless backend relays outbound TCP through the selected proxy from the parent-side engine
-U, --proxy-user <PROXY_USER>
Username for upstream proxy authentication
-P, --proxy-password <PROXY_PASSWORD>
Password for upstream proxy authentication
--proxy-insecure
Ignore certificate trust errors for https:// upstream proxies while still validating the hostname
--summary
Print a post-run summary to stderr
--flow-log <FLOW_LOG>
Write structured flow events as JSON Lines. Currently supported only by the default rootless backend
--offline
Block all outbound networking for the child tree, including DNS forwarding
--block-private
Block child-tree traffic to private, loopback, link-local, and ULA-style destinations
--block-metadata
Block common cloud metadata endpoints such as 169.254.169.254
--default-policy <DEFAULT_POLICY>
Choose whether unmatched outbound destinations are allowed or denied [default: allow] [possible values: allow, deny]
--allow-cidr <ALLOW_CIDRS>
Allow outbound destinations that fall within this IPv4 or IPv6 CIDR
--deny-cidr <DENY_CIDRS>
Deny outbound destinations that fall within this IPv4 or IPv6 CIDR
--proxy-only
Require outbound traffic to use the configured upstream proxy path
--fail-on-leak
Exit non-zero if childflow blocks traffic that the child process did not treat as fatal. Currently supported only by the default rootless backend
-i, --iface <IFACE>
Force the host-side egress interface for the child's direct traffic
-h, --help
Print help
-V, --version
Print version
CLI Examples
Basic
Run one command tree with the default rootless backend:
Capture only that tree's traffic:
Force DNS resolution through a specific resolver:
Override /etc/hosts for just this command tree:
Policy
Run completely offline:
Block common cloud metadata endpoints:
Block private, loopback, and link-local destinations:
Switch to default-deny and allow only one destination:
Block a destination range explicitly:
Proxy
Force a simple HTTP proxy path:
Run a tool that would not normally honor proxy environment variables:
Use an authenticated HTTPS upstream proxy:
Require all outbound TCP to use the configured proxy path:
Treat blocked direct traffic as a failed run:
Profiles
Run a stored profile as-is:
Load a profile and still override the command on the CLI:
Inspect the merged effective profile after CLI overrides:
Observability
Write a structured flow log for later inspection:
Rootful
Use the rootful backend when you need host-integrated behavior:
ICMP and Traceroute
Run ping inside the isolated command tree:
Run traceroute inside the isolated command tree:
Description
Backend Summary
| Feature | rootless-internal |
rootful |
|---|---|---|
| Isolated execution | Yes | Yes |
| DNS override | Yes | Yes |
/etc/hosts override |
Yes | Yes |
| Outbound TCP | Yes | Yes |
| UDP relay | Yes | Yes |
| Proxy support | Yes, via parent-side relay engine | Yes, via transparent interception path |
| Policy controls | Yes | Yes |
| Structured flow log | Yes | Not yet |
--fail-on-leak |
Yes | Not yet |
| Transparent proxy / TPROXY | No | Yes |
--iface |
No | Yes |
| Packet capture | Optional, with child, egress, wire-egress, and both views |
Optional, with child, egress, wire-egress, and both views |
| Status | Default and recommended path | Advanced fallback for features that still require host-side networking |
Use rootless-internal by default. It is the main path for isolated execution, DNS control, proxying, packet capture, ping, and traceroute without host-wide rootful setup.
Use --root when you specifically need host-integrated behavior that the rootless path does not expose yet, including:
- transparent proxying
- interface-forced direct egress with
--iface - broader raw-ICMP behavior than the current rootless relay engine implements
Policy Controls
childflow can treat the command tree as a small outbound policy domain.
--offlinedeny all outbound traffic and disable DNS forwarding--block-privatedeny private, loopback, link-local, and ULA-style destinations--block-metadatadeny common cloud metadata endpoints--default-policy denydeny destinations unless they match an explicit allow rule--allow-cidrallow IPv4 or IPv6 CIDRs--deny-cidrdeny IPv4 or IPv6 CIDRs--proxy-onlyrequire outbound traffic to use the configured proxy path--fail-on-leakreturn non-zero when childflow blocks traffic but the child process still exits0
Current notes:
--proxy-onlyis primarily a TCP-focused control; in the rootless backend, direct DNS / UDP / ICMP traffic is also blocked rather than relayed--fail-on-leakis currently supported only byrootless-internal
Profiles
childflow can load reusable TOML profiles with --profile.
= "./base.toml"
= "./captures/run.pcapng"
= "./logs/run.jsonl"
= "1.1.1.1"
= "rootless-internal"
= true
= true
= "deny"
= ["203.0.113.10/32"]
= ["curl", "https://203.0.113.10/healthz"]
You can also print the merged effective profile after CLI overrides:
Current notes:
- profile files currently use TOML
- profiles can inherit from a shared base with
extends = "./base.toml" - merge order is: parent profile, child profile, then explicit CLI flags
- CLI flags override profile values when both are present
- for list-valued settings such as
allow_cidrsanddeny_cidrs, explicit CLI flags replace the profile list instead of appending to it - an explicit CLI command after
--replaces the profilecommand --dump-profileprints the merged effective TOML and exits without running the command- relative paths inside a profile are resolved relative to the profile file itself
- profile keys use command-oriented names such as
capture,capture_point,backend,flow_log,default_policy,allow_cidrs, anddeny_cidrs --rootremains a CLI-only convenience flag; usebackend = "rootful"in profiles when you want the rootful backend- the fuller key-by-key schema is documented in docs/profile-schema.md
Flow Log
childflow can emit structured JSON Lines flow events with --flow-log.
Current event types:
dns_querydns_answerconnect_attemptconnect_resultpolicy_violationflow_end
Current schema notes:
- every event includes
schema_version: 1 connect_attempt,connect_result, andflow_endinclude stableremote_ip/remote_portfieldsconnect_result.statusis currently one ofokorerrordns_queryanddns_answerinclude stableserver_ip/server_portfieldsdns_answer.modeis currently one ofrelayedorsynthetic_emptypolicy_violationincludes structured fields such asaction,reason_code,control, andmatched_cidrwhen applicable
Current notes:
--flow-logis currently supported only byrootless-internal- each line is standalone JSON, so it is easy to inspect with tools such as
jq - flow logs complement
--capture; use--capturefor packet-level inspection and--flow-logfor higher-level execution tracing --summarywill also show aggregate flow-log event counts after the run- the fuller event-by-event schema is documented in docs/flow-log-schema.md
Capture Modes
childflow is intended to capture only the target command tree's traffic, not unrelated host traffic.
The default child mode keeps the isolated child-side view.
egresssynthetic egress-oriented view on both backendswire-egressreal host egress capture on both backendsbothwrites sibling.child.pcapngand.egress.pcapngfiles
Generated pcapng files also embed metadata describing the capture view, backend, kind, and interface.
For the fuller comparison of current capture points and the planned child / egress / wire-egress / both capture-point direction, see docs/technical-details.md.
License
MIT. See LICENSE.