summaryrefslogtreecommitdiff
path: root/internal/wireguard
diff options
context:
space:
mode:
authorJames O'Doherty <james@theodohertyfamily.com>2026-06-04 22:38:44 -0400
committerJames O'Doherty <james@theodohertyfamily.com>2026-06-04 22:38:44 -0400
commit66b782e261f1cd928ad6a8482788a65fb484db45 (patch)
tree38b6c46200d9c4464affc1c0c43494a5555acf33 /internal/wireguard
parentc53503b52b6fc6de37b6053719521054003fa50b (diff)
refactor: simplify architecture and improve documentation
- 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.
Diffstat (limited to 'internal/wireguard')
-rw-r--r--internal/wireguard/wireguard.go33
1 files changed, 32 insertions, 1 deletions
diff --git a/internal/wireguard/wireguard.go b/internal/wireguard/wireguard.go
index 0c341f2..cea9590 100644
--- a/internal/wireguard/wireguard.go
+++ b/internal/wireguard/wireguard.go
@@ -1,5 +1,24 @@
//go:build linux
+// Package wireguard provides the userspace WireGuard implementation and TUN device binding.
+//
+// Data Flow:
+// 1. Egress: A process sends a packet. The Linux kernel routes it via tun0. The userspace
+// WireGuard device reads this packet, encrypts it, and sends it as a UDP packet to the
+// remote endpoint via the preserved host socket.
+// 2. Ingress: A UDP packet arrives via the host socket. The userspace WireGuard device
+// decrypts it and writes the raw IP packet back into the TUN device, delivering it to
+// the process.
+//
+// MTU Management:
+// WireGuard adds overhead. To prevent fragmentation and packet loss, the TUN device
+// MTU is set to 1420 bytes.
+//
+// DNS Isolation:
+// To prevent DNS leaks, wg-wrap isolates the namespace's DNS resolution by:
+// 1. Creating a temporary resolv.conf within the profile's runtime directory.
+// 2. Bind-mounting this file over /etc/resolv.conf inside the namespace.
+// 3. Falling back to trusted public DNS (e.g., 1.1.1.1) if no DNS server is configured.
package wireguard
import (
@@ -25,7 +44,9 @@ import (
// Tunnel represents an active Userspace WireGuard tunnel inside a network namespace.
type Tunnel struct {
- Device *device.Device
+ // Device is the wireguard-go device instance.
+ Device *device.Device
+ // Tun is the underlying TUN device.
Tun tun.Device
dnsFile string
}
@@ -241,6 +262,7 @@ func GetTunnelLocalIP(cfg *wgconf.Config) (string, error) {
return ip.String(), nil
}
+// ConfigureResolvConf creates a temporary resolv.conf file and bind-mounts it to /etc/resolv.conf.
func ConfigureResolvConf(dns string, profileDir string) (string, error) {
if dns == "" {
return "", nil
@@ -271,6 +293,7 @@ func ConfigureResolvConf(dns string, profileDir string) (string, error) {
return launcherPath, nil
}
+// UnmountResolvConf unmounts the bind-mounted resolv.conf and removes the temporary file.
func UnmountResolvConf(path string) error {
if path == "" {
return nil
@@ -286,6 +309,8 @@ func UnmountResolvConf(path string) error {
return nil
}
+// BlockHostServices bind-mounts empty files/directories over sensitive host services
+// to prevent access from within the isolated namespace.
func BlockHostServices(pm *paths.PathManager, profile string) error {
blockDirBase := filepath.Join(pm.RuntimeBaseDir(), "profiles", profile, "block")
if err := os.MkdirAll(blockDirBase, 0755); err != nil {
@@ -321,8 +346,10 @@ func BlockHostServices(pm *paths.PathManager, profile string) error {
return nil
}
+// HostBind is a placeholder bind implementation for WireGuard.
type HostBind struct{}
+// NewHostBind creates a new HostBind instance.
func NewHostBind(inner conn.Bind, hostNetNSFd int) *HostBind {
return &HostBind{}
}
@@ -337,11 +364,14 @@ func (h *HostBind) Send(bufs [][]byte, endpoint conn.Endpoint) error { return ni
func (h *HostBind) ParseEndpoint(s string) (conn.Endpoint, error) { return nil, nil }
func (h *HostBind) BatchSize() int { return 0 }
+// FDBind implements wireguard-go's conn.Bind using an existing file descriptor.
+// This allows the tunnel to use a UDP socket opened on the host.
type FDBind struct {
originalFd int
conn *net.UDPConn
}
+// FDEndpoint implements wireguard-go's conn.Endpoint for file-descriptor based binds.
type FDEndpoint struct {
addr netip.AddrPort
}
@@ -354,6 +384,7 @@ func (e *FDEndpoint) SrcIP() netip.Addr { return netip.Addr{} }
func (e *FDEndpoint) SrcToString() string { return "" }
func (e *FDEndpoint) SrcIfidx() int32 { return 0 }
+// NewFDBind creates a new FDBind instance from a raw file descriptor.
func NewFDBind(fd int) (*FDBind, error) {
return &FDBind{originalFd: fd}, nil
}