DaeNext is the Rust-native dae core workspace.
dae, which means goose, is a high-performance transparent proxy solution. To keep traffic split fast, dae uses Linux eBPF and transparent proxying so direct traffic can bypass userspace forwarding while proxied traffic is handled by the runtime.
DaeNext keeps that architecture while moving the daemon, routing, DNS, configuration, outbound protocols, native eBPF loader, and shared runtime contracts into a Rust workspace.
- Rust-native workspace for the dae core runtime, CLI, daemon, routing, DNS, datapath, outbound protocols, and product contracts.
- Native Aya/eBPF datapath support for transparent proxy routing, cgroup ownership checks, listener handoff, routing maps, and runtime map diagnostics.
- Real transparent proxy semantics for direct and proxied traffic instead of endpoint-only or synthetic routing shortcuts.
- Configuration parsing, materialization, and golden fixture coverage for dae-compatible runtime behavior.
- Resident TCP/UDP dataplane workers for policy-based forwarding, health checks, latency probing, and group strategy state.
- Support for DNS routing, domain routing map updates, geodata matching, and runtime connectivity state.
- Support for common proxy protocols through the Rust outbound stack, including TLS, uTLS/BoringSSL paths, HTTP/2, HTTP/3, QUIC, xHTTP, VLESS, VMess, Shadowsocks, Trojan, SOCKS, and related transports where implemented.
- Build, release, benchmark, and golden-test tooling rooted at the repository top level.
The resident runtime currently supports the combinations below. “UDP over stream” means that UDP packets are carried inside the protocol's ordered stream; it does not imply that the network underlay itself is UDP.
| Protocol | Transport and security | Supported traffic |
|---|---|---|
| Shadowsocks AEAD | Native | TCP stream and AEAD UDP datagram |
| Shadowsocks 2022 | Native | TCP stream and 2022 UDP datagram |
| SOCKS5 | CONNECT / UDP ASSOCIATE | TCP and UDP |
| HTTP proxy | CONNECT | TCP |
| VLESS Vision | TLS over TCP | TCP and XUDP |
| VLESS | TLS over WebSocket | TCP and UDP over stream |
| VLESS | TLS over HTTPUpgrade | TCP and UDP over stream |
| VLESS | TLS over gRPC | TCP and UDP over stream |
| VLESS Vision | Reality over TCP | TCP and XUDP |
| VLESS xHTTP | TLS, H2/H3, auto/stream-up/packet-up | TCP and UDP |
| VLESS xHTTP | Reality, packet-up | TCP and UDP |
| VMess AEAD | TCP | TCP and UDP over stream |
| VMess AEAD | WebSocket | TCP and UDP over stream |
| VMess AEAD | HTTPUpgrade | TCP and UDP over stream |
| VMess AEAD | TLS over gRPC | TCP and UDP over stream |
| Trojan | TLS over TCP | TCP and UDP over TCP |
| Trojan | TLS over WebSocket | TCP and UDP over stream |
| Trojan | TLS over HTTPUpgrade | TCP and UDP over stream |
| Trojan | TLS over gRPC | TCP and UDP over stream |
| Hysteria2 | QUIC | TCP over QUIC stream and QUIC datagram UDP |
| TUIC | QUIC | TCP and UDP |
| Juicity | QUIC | TCP and UDP |
| AnyTLS | TLS | TCP and packet-stream UDP |
Current limits:
- Ordinary HTTP CONNECT does not provide UDP relay semantics. CONNECT-UDP or MASQUE would require a separate implementation.
- gRPC wrappers accept uncompressed inbound hunks. Compressed inbound hunks are fail-closed.
- xHTTP uses the same-listener session model. A separately configured download endpoint must carry its complete transport and security settings.
- Fingerprint-aware TLS is supported through the resident underlay, but this project does not claim complete Go-uTLS wire parity for every fingerprint mode.
- Unsupported packet chains fail closed instead of silently falling back to a direct connection or a different transport.
DaeNext is a Cargo workspace. Build, test, fixture, and release paths are rooted at the repository root.
The dae CLI requires stable Rust and a native C/C++ toolchain. A production
daed build with the default features additionally requires:
- Rust nightly with the
rust-srccomponent, used for the embedded eBPF objects; bpf-linker,clang, LLVM, and libelf development headers;- CMake, Perl,
pkg-config, and a C/C++ compiler for BoringSSL and native dependencies.
Format the workspace:
cargo fmt --allCheck all targets:
cargo check --workspace --all-targetsRun library tests:
cargo test --workspace --libRun the service contract tests:
cargo test -p dae-daemon --test service_contractBuild the Rust dae binary:
cargo build --locked --release -p dae-cli --bin daeBuild the Rust-native daed product binary:
cargo build --locked --release -p dae-daemon --bin daedThe default dae-daemon feature set is the production set. It includes the
product API, resident runtime, native Aya/eBPF loader, jemalloc, and the
BoringSSL TCP-TLS and QUIC providers. Rustls and AWS-LC are not part of the
production dependency graph.
| Parameter | Meaning |
|---|---|
--locked |
Requires the dependency versions recorded in Cargo.lock; use it for reproducible builds. |
--release |
Uses Cargo's optimized release profile: optimization level 3, fat LTO, one codegen unit, and an unstripped output. |
--target <triple> |
Selects the Rust compilation target, for example aarch64-unknown-linux-gnu. The matching Rust target and cross linker must be installed. |
--profile production-performance |
Uses the workspace production profile: optimization level 3, fat LTO, one codegen unit, and an unstripped output. |
--profile production-size |
Uses the size profile: opt-level=z, one codegen unit, no LTO, stripped output. |
CARGO_TARGET_DIR |
Moves Cargo artifacts to a separate cache/output directory. Use separate directories when building different CPU levels concurrently. |
CARGO_PROFILE_RELEASE_LTO=fat |
Selects the default release LTO mode. Override only for a controlled comparison build. |
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 |
Selects the default release codegen-unit count. Override only for a controlled comparison build. |
RUSTFLAGS="-C target-cpu=..." |
Selects the minimum CPU instruction baseline. It affects compatibility and must match the artifact label. |
DAE_DAEMON_VERSION |
Overrides the complete version text embedded in daed --version; product builds normally set this automatically. |
DAE_RUST_NATIVE_BPF_TOOLCHAIN |
Selects the Rust toolchain used to build the embedded eBPF objects; the default is nightly. |
DAE_RUST_NATIVE_BPF_OBJECT |
Reuses a prebuilt generic native eBPF object instead of rebuilding it. The object is still validated before embedding. |
DAE_RUST_NATIVE_BPF_PNAME_CORE_OBJECT |
Reuses the corresponding prebuilt process-name CO-RE eBPF object. |
Recommended distributable CPU baselines:
| Artifact | RUSTFLAGS |
Compatibility |
|---|---|---|
| x86_64 v1 | -C target-cpu=x86-64 |
Baseline x86-64 systems. |
| x86_64 v2 | -C target-cpu=x86-64-v2 |
Modern x86-64 systems with the v2 ISA level; no AVX2 requirement. |
| x86_64 v3 | -C target-cpu=x86-64-v3 |
AVX2-class systems; do not install on v1/v2-only CPUs. |
| ARM64 generic | -C target-cpu=generic |
Baseline AArch64/ARMv8-A, including Cortex-A53 at the ISA level. |
For example, build a reproducible x86_64-v2 daemon with the default Fat LTO profile:
CARGO_PROFILE_RELEASE_LTO=fat \
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 \
RUSTFLAGS="-C target-cpu=x86-64-v2" \
cargo build --locked --release -p dae-daemon --bin daedDo not use target-cpu=native for a redistributable binary: it may enable
instructions that are unavailable on the destination host. OpenWrt package
architecture names such as aarch64_generic and aarch64_cortex-a53 are
package-manager labels, not Rust CPU tuning values.
| Feature | Purpose |
|---|---|
default |
Production daemon graph: product API, resident runtime, native eBPF, jemalloc, and BoringSSL providers. Keep this for normal builds. |
product-api |
Enables the daed product API and its persistence/authentication dependencies. The daed binary requires it. |
resident-runtime |
Enables the production resident dataplane runtime. |
native-ebpf |
Builds and embeds the Aya eBPF objects and enables the native loader. |
allocator-jemalloc |
Selects jemalloc and its runtime statistics/reclaim controls; this is the production default. |
allocator-system |
Selects the system allocator for controlled comparison builds. It is mutually exclusive with allocator-jemalloc, so it requires a complete --no-default-features feature list. |
Setting allocator_idle_reclaim_enabled: false disables periodic idle reclaim;
explicit lifecycle and control-plane requests still run through the coordinator's
activity checks. A stopped runtime counts as zero traffic once cleanup finishes.
Emergency cgroup usage bypasses the ordinary reclaim cooldown even when
memory.high is unset. Application objects that remain live are not freed by
allocator reclaim.
TCP raw relay buffers are released after 30 seconds without progress once their pending bytes have been written, and allocated again when data becomes readable. UDP session idle deadlines follow accepted traffic in both directions, including empty datagrams. Rejected responses do not renew a session. Datagram scratch buffers use the profile's 15/30/60-second idle timeout; stream framing buffers retain incomplete messages. UDP queued work and downstream packet rates also participate in allocator activity checks. Runtime workers acknowledge cache flush epochs without waiting for their peers; missing acknowledgments produce a bounded partial result.
Automatic UDP session admission uses 32/128/512 MiB resource budgets for the
low-memory/balanced/high-performance profiles, with a 128 KiB reservation estimate
per session (256/1024/4096 sessions). This estimate is not measured RSS; queued
payloads and shared transports have separate budgets. RESIDENT_UDP_SESSION_LIMIT
overrides the automatic count limit. At 85% of the lower finite cgroup
memory.high/memory.max limit, new session admission is rejected until pressure
subsides, and the idle UDP payload pool is cleared; existing sessions continue.
Normal idle pool maintenance retains
at most one warm buffer per shard after 30 seconds. Pressure sampling continues
when automatic allocator reclaim is disabled. Retired generations keep their
independent deadlines and count limits; session activity does not extend them.
On Linux glibc, allocator-system builds now execute malloc_trim by default for
explicit requests and urgent cgroup pressure after activity checks. They do not
have jemalloc statistics or dedicated control-plane arenas, so these trims are
process-wide. Set ALLOCATOR_SYSTEM_TRIM=0 to opt out for comparison runs; the
legacy DAED_ALLOCATOR_SYSTEM_TRIM variable remains a fallback. Other system
allocator targets report trim as unsupported.
Features prefixed with test- are internal A/B or regression switches. The
historically named test-boringssl-tcp-tls and test-boringssl-quic gates are
already part of the current production default and select the sole admitted
BoringSSL providers. Other test-* switches must not be enabled in release
artifacts unless running the corresponding controlled experiment.
Inspect the effective feature graph when changing a build configuration:
cargo tree -p dae-daemon -e featuresRun the same gate used by CI and release:
scripts/release_gate.shFor product-level usage documentation, refer to the upstream dae documentation: Quick Start Guide.
- DaeNext is the Rust-native core workspace. Product packaging and the
daedWebUI release remain owned by the product release workflow that consumes this workspace as its core. - Linux eBPF availability and kernel feature gates matter for resident transparent proxy mode. The runtime performs preflight checks before attaching production dataplane programs.
- UDP is stateful in the dataplane through kernel maps and timer-backed cleanup. Map capacity should be tuned through profile/load-time configuration and occupancy diagnostics, not by changing live BPF map sizes at runtime.
- Keep behavior-compatible changes aligned with dae's user-facing semantics: parser support, admission support, and real wire/proxy behavior are separate validation layers.
DaeNext follows dae's transparent proxy model:
- eBPF programs classify traffic, perform direct/proxy split decisions, and maintain routing, redirect, process, domain, and UDP state maps.
- The Rust daemon owns runtime configuration, resident dataplane workers, health checks, latency probes, DNS behavior, outbound protocol execution, and product-facing contracts.
- Direct traffic remains on the kernel fast path where possible, while proxied traffic is handed to userspace workers with the same policy and protocol semantics expected by dae.
For the original product architecture, see upstream dae's How it works.
crates/: Rust crates for the daemon, control plane, routing, DNS, datapath, outbound protocols, eBPF support, CLI tools, and shared contracts.build/: shared build helpers used by crate build scripts.scripts/: repository maintenance and validation scripts.testdata/: golden fixtures and common test inputs.example.dae: example runtime configuration.
- Keep Rust-native dataplane behavior aligned with dae's Go/eBPF contract.
- Continue expanding protocol parity and live evidence coverage.
- Improve runtime map occupancy diagnostics and profile guidance.
- Keep product packaging boundaries explicit between this workspace and the
daedproduct release.
Special thanks goes to the dae community and all contributors. For upstream dae contribution guidance, see the contribution instructions and the commit message guide.
This project originates from the dae project: https://github.com/daeuniverse/dae.
