| Age | Commit message (Collapse) | Author |
|
This commit refactors the core system operations to use a manager-based
dependency injection pattern, eliminating global state and resolving
data races in the test suite.
Architecture:
- Introduced NetworkManager and NetworkOps interface in internal/network
to abstract netlink calls.
- Introduced MountOps and FileSystem interfaces in internal/namespace
to abstract mount and filesystem operations.
- Introduced TunnelManager in internal/wireguard to coordinate tunnel
lifecycle using the new abstractions.
- Updated internal/cli and internal/manager to use these managers.
Testing:
- Restored t.Parallel() to unit tests in internal/network and
internal/wireguard.
- Implemented setupParallelEnv and an enhanced mockFS in
wireguard_unit_test.go to ensure complete test isolation.
- Added bootstrap_test.go to verify launcher preparation logic in
internal/namespace without requiring syscall.Exec.
- Resolved data races in internal/network tests.
CLI:
- Added support for -h, --help, and -help flags for the main command.
Verification:
- Passed all tests (unit, integration, E2E).
- Verified zero data races with 'go test -race'.
- Passed golangci-lint and go vet.
|
|
Prevent the ambiguity where a mistyped subcommand was interpreted as the target
wrapped process.
- Introduce `run` and `exec` (alias) subcommands for launching wrapped processes.
- Promote internal test commands (`test-ns`, `test-args`, `test-lifecycle`) to explicit subcommands.
- Update CLI routing to return an error for unknown subcommands instead of falling back to the default execution path.
- Update `README.md` usage examples and all test suites to use the new subcommand structure.
|
|
WireGuard profile files contain sensitive private keys. Previously, these files were written with 0644 permissions, making them world-readable. This commit changes the file mode to 0600 to ensure only the owner can read and write the profiles.
- Updated `handleProfileImport` to use 0600 permissions.
- Added tests to verify that imported profiles have the correct permissions.
|
|
Implement custom usage functions to provide more comprehensive and
discoverable help messages for the top-level tool and profile
management subcommands.
- Add printUsage and printProfileUsage methods to App.
- Override FlagSet.Usage to display professional help messages.
- Ensure profile subcommands are listed in the main help output.
- Trigger profile usage on missing or invalid subcommands.
|
|
Eliminate the external dependency on the `ip` (iproute2) command-line tool by centralizing network configuration and diagnostics within a new `internal/network` package using the `netlink` library.
Changes:
- Introduced `internal/network` package to handle network interface listing and configuration.
- Replaced `exec.Command("ip", "link")` in `internal/namespace.VerifyIsolation` with `network.ListInterfaces()`.
- Improved `VerifyIsolation` to explicitly ensure only the loopback interface is present in a fresh network namespace.
- Moved interface and routing configuration logic from `internal/wireguard` to `internal/network`.
- Removed unnecessary `os/exec` imports from network-related files.
This change increases the tool's portability by removing the requirement for `iproute2` to be installed in the target environment.
|
|
- Introduce `namespace.Ops` interface to decouple `Manager` from system-level namespace operations, enabling easier unit testing via mocks.
- Add unit tests for `internal/paths` to verify path resolution logic across different environment configurations.
- Implement `EnsureBinary` helper in E2E tests to gracefully skip tests when `WG_WRAP_BIN` is not set, allowing `go test ./...` to pass in non-build environments.
- Apply project-wide formatting and fix linting issues.
|
|
- Extract orchestration logic from `internal/cli` into a new `internal/manager` package for better composability.
- Migrate technical implementation details from README.md to package-level godoc strings.
- Rewrite README.md to be more user-centric, focusing on quick start and usage.
- Add comprehensive documentation for exported structs and fields across the project.
- Verify all changes with `go fmt`, `go vet`, `golangci-lint`, and full E2E test suite.
|
|
- Remove leftover DEBUG prints from CLI and wireguard internal packages.
- Silence stdout during successful command wrapping to ensure only the wrapped command's output is visible.
- Redirect all warnings and internal errors to stderr.
- Implement a verbose mode via `WG_WRAP_VERBOSE=1` to enable tunnel status messages.
- Update E2E tests to use verbose mode for verification of tunnel lifecycle events.
- Fix errcheck linting issue in wireguard.go and apply go fmt.
|
|
- Fix DNS resolver leaks by creating temporary resolv.conf files within the profile's runtime directory and ensuring robust cleanup.
- Fix isolation block directory leaks by explicitly removing the block directory during namespace unpinning.
- Improve namespace lifecycle management:
- Register processes before joining an active namespace to prevent race conditions in reference counting.
- Update `IsLastProcess` and corresponding tests to reflect the unregister-then-check cleanup flow.
- Improve test reliability and correctness:
- Convert `TestAppRun_ProfileDirInjection` to use separate binary execution, preventing process replacement and ensuring `t.TempDir()` cleanup.
- Replace hardcoded test configuration paths with `t.TempDir()` in `mount_leak_test.go`.
- Implement `SetEnvOverrides` helper for cleaner environment variable management in E2E tests.
- Improve E2E lifecycle tests with better environment handling and output redirection.
|
|
public domain license
- Update go.mod and all internal imports to reflect the new module path
- Add LICENSE file with the Unlicense (public domain dedication)
- Increase timeouts in e2e lifecycle tests to prevent flaky failures
- Verify all tests, linting, and formatting pass with the new module name
|
|
- Improve routing logic in CLI for better readability.
- Resolve flakiness in `TestNamespaceLifecycleAutomation` by increasing polling timeouts and adjusting tick intervals.
- Verify project state with `go fmt`, `go vet`, and `golangci-lint`.
- Ensure all unit and E2E tests pass deterministically.
|
|
- fix(cli): resolve Flock self-deadlock in ExecuteCommand cleanup by reusing the existing lockFile handle if already held during premature exit.
- fix(wireguard): configure explicit default route destination (0.0.0.0/0 for IPv4 and ::/0 for IPv6) to avoid netlink "either Dst.IP, Src.IP or Gw must be set" error.
- fix(wireguard): initialize the Tunnel return parameter in StartTunnel to prevent a nil pointer dereference.
- test(e2e): fix argument ordering in waitForLifecycle to pass "test-lifecycle" first, and increase sleep duration of dummy processes to 1.0s to ensure reliable process persistence under race detection.
|
|
- Added `test-lifecycle` CLI command to verify active session state.
- Replaced manual filesystem polling and `time.Sleep` in E2E tests with `waitForLifecycle` synchronization.
- Optimized `TestConfigHotSwap` by reducing artificial sleep durations.
- Fixed linting issue (ST1023) in `internal/cli/cli.go`.
These changes reduce total test execution time to under 15 seconds and improve the determinism of lifecycle verification.
|
|
- Security: Eliminate namespace escape risk by removing `HostBind` and enforcing `FDBind` using pre-opened host socket FDs.
- Security: Replace unsafe `atoi` with `strtol` and strict validation in the C launcher to prevent malformed PID joins.
- Stability: Fix PID wraparound by storing session timestamps in PID files to detect recycled PIDs.
- Stability: Resolve DNS mount leaks by implementing proper unmounting of `/etc/resolv.conf` during tunnel shutdown.
- Performance: Optimize `FDBind` throughput by implementing batch packet processing in the receive loop.
- Deployment: Implement `memfd_create` for the C launcher to support `noexec` temporary directories and reduce disk I/O.
- Maintenance: Replace external `ip` CLI dependency with native `netlink` library for robust network configuration.
- Quality: Fix all `golangci-lint` errors and replace remaining panics with explicit error handling.
|
|
- Simplify namespace bootstrapping by introducing `prepareLauncher` helper
- Implement a cleanup stack in `StartTunnel` to ensure orderly resource release on error
- Streamline temporary file and mount lifecycles in `ConfigureResolvConf` and `BlockHostServices`
- Ensure `Tunnel.Close()` also closes the underlying TUN device
- Reduce redundant manual cleanup calls using defer-based error handling
|
|
- Replace marker-file pinning with kernel bind-mount anchors for reliable namespace persistence.
- Implement atomic "last-man-out" cleanup sequence using ProfileLock, preventing namespace leaks and race conditions.
- Add comprehensive resilience test suite covering:
- Crash recovery from stale runtime state.
- Host network change stability.
- Configuration hot-swap session persistence.
- Resource exhaustion and high-churn lifecycle stress.
- Align documentation and test expectations with rootless session-based persistence.
- Fix argument integrity and isolation leaks.
- Ensure 100% pass rate for all E2E and integration tests.
|
|
Fix an architectural shortfall where concurrent sessions failed to share
the target network and mount namespaces. Because the Go runtime is
multi-threaded, calling unix.Setns with CLONE_NEWNS from Go always returned
EINVAL, silently forcing concurrent runs to fall back to bootstrapping separate
isolated namespaces and separate WireGuard connections.
This commit resolves the issue by extending the embedded single-threaded C
launcher to handle namespace joining, and introducing a host-to-isolated path
propagation pattern:
1. Launcher setns Support: The C launcher now checks for WG_WRAP_JOIN_PID in
the environment. If present, it joins the User, Mount, and Network
namespaces of the active PID in single-threaded mode before executing the Go
binary.
2. BootstrapJoin Integration: Implemented namespace.BootstrapJoin to
transition joining sessions via the launcher.
3. Path Preservation: Export WG_WRAP_HOST_RUNTIME_BASE_DIR from the host to ensure
the isolated instance maps the profile and PID directories to the exact
same location.
4. Redundant Tunnel Bypass: Detect joined sessions via WG_WRAP_JOINED=1 in the CLI
and bypass starting a duplicate WireGuard tunnel on the occupied tun0.
5. Testing: Added tests/e2e/sharing_test.go to assert namespace ID equality,
which now passes successfully.
6. Git Tracking: Fixed .gitignore overmatch to stop ignoring cmd/wg-wrap/.
|
|
- DNS Leak / Isolation Bypass: Blocked glibc's systemd-resolved and
D-Bus socket communication within the unprivileged mount namespace by
introducing BlockHostServices(). This targeted mount-blocking forces
glibc to fall back to the standard resolv.conf DNS routing path and
prevents host leaks.
- Lifecycle Race: Reordered and protected the reference-counting
cleanup routine under the profile flock to ensure that check-and-unpin
operations are atomic and do not teardown namespaces actively used
by parallel processes.
- Editor Arguments: Split the EDITOR environment variable into discrete
field tokens before invocation to support editor configurations
containing command-line flags.
- Testing: Added E2E regression tests for DNS leak detection,
namespace unpinning concurrency, and editor argument parsing. All E2E
tests now compile and pass cleanly.
|
|
concurrency races, and resource leaks
This commit addresses several security vulnerabilities, undefined behaviors, race conditions, and resource leaks across the application:
1. Path Traversal & Arbitrary File/Directory Actions:
- Implemented `IsValidProfileName` in `internal/cli/cli.go` to restrict profile names to alphanumeric characters, dashes, and underscores.
- Applied validation to all CLI paths (`--profile`, `import`, `configure`, `delete`, `stop`) to prevent directory traversal and unauthorized directory or file creations/deletions.
- Added `TestIsValidProfileName` in `internal/cli/cli_test.go`.
2. Network Namespace Escape via Compromised Thread recycling:
- Fixed `HostBind.Open` in `internal/wireguard/wireguard.go` to panic immediately instead of returning an error if restoring the isolated namespace fails. This prevents Go from returning the compromised thread (still in host namespace) to the runtime pool.
3. Concurrency Race Conditions & Thread Migration:
- Added `runtime.LockOSThread()` in `JoinExistingNamespace` (`internal/namespace/pinning.go`) to ensure the goroutine stays on the modified namespace thread before executing the command.
- Implemented profile locking using advisory file locks (`unix.Flock`) on a `.lock` file in the user's runtime directory (with platform stubs in `internal/namespace/lock_linux.go` and `internal/namespace/lock_stub.go`).
- Integrated locking during `App.Run` and `App.ExecuteCommand`, releasing the lock right before spawning the wrapped process.
4. File Descriptor Leaks on Bootstrap Failures:
- Refactored `Bootstrap()` in `internal/namespace/namespace.go` to use named return values and a deferred cleanup loop that closes `execFd`, `hostNetFd`, and the duplicated `hostSocketFd` if `syscall.Exec` fails.
- Added an explicit `conn.Close()` on the original socket connection after duplication.
5. Glibc Undefined Behavior / Crash on argc == 0:
- Corrected `internal/namespace/launcher_src/launcher.c` to not reference `argv[0]` when `argc < 1`. Recompiled `internal/namespace/launcher.bin`.
6. DNS Fallback Usability & Import Safety:
- Added validation in `ExecuteCommand` to issue a warning when falling back to `1.1.1.1` if the configuration does not route all traffic (`0.0.0.0/0` or `::/0`).
- Prevented silent overwrites in `handleProfileImport` if the destination profile already exists, and added a corresponding unit test verifying failure.
|
|
Upgrades several indirect and direct dependencies to their latest safe versions,
successfully resolving 26 dormant vulnerabilities identified by govulncheck.
- Upgraded golang.org/x/crypto from v0.37.0 to v0.52.0 (remediating 13 CVEs)
- Upgraded golang.org/x/net from v0.39.0 to v0.55.0 (remediating 12 CVEs)
- Upgraded golang.org/x/sys from v0.32.0 to v0.45.0 (remediating 1 CVE)
- Upgraded golang.zx2c4.com/wireguard to v0.0.0-20260522210424-ecfc5a8d5446
Ran `go mod tidy` and verified that all unit, integration, and E2E
data-plane tests continue to compile and pass successfully.
|
|
parser for robustness
- CLI:
- Add optional `[name]` argument to `wg-wrap profile import <path> [name]` to allow overriding the imported profile name. If not provided, it falls back to the derived filename.
- Update `README.md` command documentation to reflect custom profile names and list the `wg-wrap profile stop <name>` subcommand.
- Expand `internal/cli/profile_test.go` to cover derived vs custom-named profile imports.
- WG Configuration Parser:
- Overhaul `pkg/wgconf/wgconf.go` to support case-insensitivity on section headers (e.g. `[peer]`, `[interface]`) and key names (e.g. `privatekey`, `allowedips`).
- Implement robust trailing comment stripping (both `#` and `;`) while preserving inline comment-like characters in cryptographic keys (e.g. `key-with-hash-inside#123`) using whitespace-padded match logic.
- Clean up and normalize leading/trailing spaces/tabs on parsed keys, values, and list elements (e.g. `AllowedIPs` and `DNS` fields).
- Gracefully ignore unrecognized keys (e.g. `MTU`, `ListenPort`, `PresharedKey`) without returning errors.
- Add comprehensive tests in `pkg/wgconf/wgconf_test.go` covering inline/block comments, formatting variations, unrecognized keys, and case-insensitivity.
|
|
- Unlink the temporary bootstrap launcher binary immediately after opening a read-only descriptor to it, then execute via `/proc/self/fd/<fd>` to ensure zero-disk footprint on execution.
- Unlink temporary `/tmp/resolvconf*` files immediately after successful bind-mounting over `/etc/resolv.conf`.
- Prune parent ephemeral profile directories when unpinning a namespace, leaving zero directories behind once empty.
- Propagate the exact exit status of the wrapped command to the host process using `errors.As` and `*exec.ExitError` instead of defaulting to exit code 1.
- Added E2E automated test `TestExitCodePropagation` to verify exit status delivery.
- Added the `$(BINARY)` target to `.PHONY` in the Makefile to delegate dependency tracking to Go's compiler cache, ensuring modified Go files are rebuilt during `make test`.
|
|
profile configuration
Completed the remaining roadmap and documentation requirements by implementing robust unprivileged DNS management, completing the profile configuration subcommand, and resolving data-plane transition socket crashes.
Detailed changes:
- **DNS Isolation**: Implemented `ConfigureResolvConf` in `internal/wireguard/wireguard.go` to override `/etc/resolv.conf` within the unprivileged network/mount namespace. Transitioned the mount namespace to private propagation (`MS_PRIVATE`) and safely bind-mounted a temporary resolv.conf file over `/etc/resolv.conf` without mutating the host's configuration.
- **DNS Precedence Order**: Integrated CLI flag `--dns-server`, parsed `.conf` interface DNS parameters, and added a safe default fallback (`1.1.1.1`) to ensure absolute host DNS leak prevention inside wrapped sessions.
- **Socket Duplication in FDBind**: Resolved a lifecycle panic in `FDBind` where `wireguard-go` called `Close` and `Open` during device state transitions, causing "use of closed network connection" errors. Implemented file descriptor duplication using `unix.Dup` during bind initialization to gracefully persist the host-socket context across interface transitions and allow clean exit synchronization.
- **Profile Configuration**: Implemented `handleProfileConfigure` in `internal/cli/cli.go` to launch the default system `$EDITOR` (falling back to `vi`) on a profile, satisfying the documentation's requirements.
- **Hermetic Testing Polish**:
- Created `dns_helpers.go` providing a `MockDNSServer` packet probe.
- Added E2E tests for unprivileged DNS resolution, data-plane UDP handshake transmission, and 3-way DNS precedence routing.
- Refactored `TestNamespaceLifecycleAutomation`, `TestConfigPropagation`, and `TestMTUFragmentation` to use default profile fallbacks, fixing failing stats on missing profiles.
- Resolved all `golangci-lint` and `go fmt` warnings to maintain a completely clean static analysis pipeline.
|
|
- Implement complete rootless network namespace bootstrap via C launcher using unshare(CLONE_NEWUSER | CLONE_NEWNS | CLONE_NEWNET).
- Resolve unprivileged network isolation blackhole via host-socket preservation (FD passing): open client UDP sockets on the host pre-isolation, clear O_CLOEXEC, and ingest them via custom `FDBind` inside the sandbox.
- Implement isolated routing table automation over `tun0` (addresses, MTU, default routes).
- Implement persistent, multi-process namespace sharing and joining using reference-counted PID files and the setns system call.
- Write robust, self-contained E2E data plane test suites in `tests/e2e/e2e_test.go` using a mock UDP listener.
- Update project documentation (`README.md` and `AGENTS.md`) to reflect completed milestones.
- Ensure 100% test passing rate and zero lint/staticcheck warnings.
|
|
- Create internal/paths package for unified config and runtime directory resolution
- Implement robust WireGuard config parsing in pkg/wgconf
- Implement profile management subcommands: list, import, configure, delete, stop
- Fix namespace pinning path collisions (separating .ns files from pids directories)
- Implement and verify namespace unpinning logic
- Fix linting errors and improve error handling across the project
|
|
|
|
|
|
tests
|
|
counting
|
|
|
|
8-bit clean argument fuzzing and portable E2E binary discovery
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|