diff --git a/dns/platform/README.md b/dns/platform/README.md deleted file mode 100644 index 0873c2f..0000000 --- a/dns/platform/README.md +++ /dev/null @@ -1,263 +0,0 @@ -# DNS Platform Module - -A standalone Go module for managing system DNS settings across different platforms and DNS management systems. - -## Overview - -This module provides a unified interface for overriding system DNS servers on: -- **macOS**: Using `scutil` -- **Windows**: Using Windows Registry -- **Linux/FreeBSD**: Supporting multiple backends: - - systemd-resolved (D-Bus) - - NetworkManager (D-Bus) - - resolvconf utility - - Direct `/etc/resolv.conf` manipulation - -## Features - -- ✅ Cross-platform DNS override -- ✅ Automatic detection of best DNS management method -- ✅ Backup and restore original DNS settings -- ✅ Platform-specific optimizations -- ✅ No external dependencies for basic functionality - -## Architecture - -### Interface - -All configurators implement the `DNSConfigurator` interface: - -```go -type DNSConfigurator interface { - SetDNS(servers []netip.Addr) ([]netip.Addr, error) - RestoreDNS() error - GetCurrentDNS() ([]netip.Addr, error) - Name() string -} -``` - -### Platform-Specific Implementations - -Each platform has dedicated structs instead of using build tags at the file level: - -- `DarwinDNSConfigurator` - macOS using scutil -- `WindowsDNSConfigurator` - Windows using registry -- `FileDNSConfigurator` - Unix using /etc/resolv.conf -- `SystemdResolvedDNSConfigurator` - Linux using systemd-resolved -- `NetworkManagerDNSConfigurator` - Linux using NetworkManager -- `ResolvconfDNSConfigurator` - Linux using resolvconf utility - -## Usage - -### Automatic Detection - -```go -import "github.com/your-org/olm/dns/platform" - -// On Linux/Unix - provide interface name for best results -configurator, err := platform.DetectBestConfigurator("eth0") -if err != nil { - log.Fatal(err) -} - -// Set DNS servers -originalServers, err := configurator.SetDNS([]netip.Addr{ - netip.MustParseAddr("8.8.8.8"), - netip.MustParseAddr("8.8.4.4"), -}) -if err != nil { - log.Fatal(err) -} - -// Restore original DNS -defer configurator.RestoreDNS() -``` - -### Manual Selection - -```go -// Linux - Direct file manipulation -configurator, err := platform.NewFileDNSConfigurator() - -// Linux - systemd-resolved -configurator, err := platform.NewSystemdResolvedDNSConfigurator("eth0") - -// Linux - NetworkManager -configurator, err := platform.NewNetworkManagerDNSConfigurator("eth0") - -// Linux - resolvconf -configurator, err := platform.NewResolvconfDNSConfigurator("eth0") - -// macOS -configurator, err := platform.NewDarwinDNSConfigurator() - -// Windows (requires interface GUID) -configurator, err := platform.NewWindowsDNSConfigurator("{GUID-HERE}") -``` - -### Platform Detection Utilities - -```go -// Check if systemd-resolved is available -if platform.IsSystemdResolvedAvailable() { - // Use systemd-resolved -} - -// Check if NetworkManager is available -if platform.IsNetworkManagerAvailable() { - // Use NetworkManager -} - -// Check if resolvconf is available -if platform.IsResolvconfAvailable() { - // Use resolvconf -} - -// Get system DNS servers -servers, err := platform.GetSystemDNS() -``` - -## Implementation Details - -### macOS (Darwin) - -Uses `scutil` to create DNS configuration states in the system configuration database. DNS settings are applied via the Network Service state hierarchy. - -**Pros:** -- Native macOS API -- Proper integration with system preferences -- Supports DNS flushing - -**Cons:** -- Requires elevated privileges - -### Windows - -Modifies registry keys under `SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{GUID}`. - -**Pros:** -- Direct registry manipulation -- Immediate effect after cache flush - -**Cons:** -- Requires interface GUID -- Requires administrator privileges -- May require restart of DNS client service - -### Linux: systemd-resolved - -Uses D-Bus API to communicate with systemd-resolved service. - -**Pros:** -- Modern standard on many distributions -- Proper per-interface configuration -- No file manipulation needed - -**Cons:** -- Requires D-Bus access -- Only available on systemd systems -- Interface-specific - -### Linux: NetworkManager - -Uses D-Bus API to modify NetworkManager connection settings. - -**Pros:** -- Common on desktop Linux -- Integrates with NetworkManager GUI -- Per-interface configuration - -**Cons:** -- Requires NetworkManager to be running -- D-Bus access required -- Interface-specific - -### Linux: resolvconf - -Uses the `resolvconf` utility to update DNS configuration. - -**Pros:** -- Works on many different systems -- Handles merging of multiple DNS sources -- Supports both openresolv and Debian resolvconf - -**Cons:** -- Requires resolvconf to be installed -- Interface-specific - -### Linux: Direct File - -Directly modifies `/etc/resolv.conf` with backup. - -**Pros:** -- Works everywhere -- No dependencies -- Simple and reliable - -**Cons:** -- May be overwritten by DHCP or other services -- No per-interface configuration -- Doesn't integrate with system tools - -## Build Tags - -The module uses build tags to compile platform-specific code: - -- `//go:build darwin && !ios` - macOS (non-iOS) -- `//go:build windows` - Windows -- `//go:build (linux && !android) || freebsd` - Linux and FreeBSD -- `//go:build linux && !android` - Linux only (for systemd) - -## Dependencies - -- `github.com/godbus/dbus/v5` - D-Bus communication (Linux only) -- `golang.org/x/sys` - System calls and registry access -- Standard library - -## Security Considerations - -- **Elevated Privileges**: Most DNS modification operations require root/administrator privileges -- **Backup Files**: Backup files contain original DNS configuration and should be protected -- **State Persistence**: DNS state is stored in memory; unexpected termination may require manual cleanup - -## Cleanup - -The module properly cleans up after itself: - -1. Backup files are created before modification -2. Original DNS servers are stored in memory -3. `RestoreDNS()` should be called to restore original settings -4. On Linux file-based systems, backup files are removed after restoration - -## Testing - -Each configurator can be tested independently: - -```go -func TestDNSOverride(t *testing.T) { - configurator, err := platform.NewFileDNSConfigurator() - require.NoError(t, err) - - servers := []netip.Addr{ - netip.MustParseAddr("1.1.1.1"), - } - - original, err := configurator.SetDNS(servers) - require.NoError(t, err) - - defer configurator.RestoreDNS() - - current, err := configurator.GetCurrentDNS() - require.NoError(t, err) - require.Equal(t, servers, current) -} -``` - -## Future Enhancements - -- [ ] Support for search domains configuration -- [ ] Support for DNS options (timeout, attempts, etc.) -- [ ] Monitoring for external DNS changes -- [ ] Automatic restoration on process exit -- [ ] Windows NRPT (Name Resolution Policy Table) support -- [ ] IPv6 DNS server support on all platforms diff --git a/dns/platform/REFACTORING_SUMMARY.md b/dns/platform/REFACTORING_SUMMARY.md deleted file mode 100644 index 44786a8..0000000 --- a/dns/platform/REFACTORING_SUMMARY.md +++ /dev/null @@ -1,174 +0,0 @@ -# DNS Platform Module Refactoring Summary - -## Changes Made - -Successfully refactored the DNS platform directory from a NetBird-derived codebase into a standalone, simplified DNS override module. - -### Files Created - -**Core Interface & Types:** -- `types.go` - DNSConfigurator interface and shared types (DNSConfig, DNSState) - -**Platform Implementations:** -- `darwin.go` - macOS DNS configurator using scutil (replaces host_darwin.go) -- `windows.go` - Windows DNS configurator using registry (replaces host_windows.go) -- `file.go` - Linux/Unix file-based configurator (replaces file_unix.go + file_parser_unix.go + file_repair_unix.go) -- `networkmanager.go` - NetworkManager D-Bus configurator (replaces network_manager_unix.go) -- `systemd.go` - systemd-resolved D-Bus configurator (replaces systemd_linux.go) -- `resolvconf.go` - resolvconf utility configurator (replaces resolvconf_unix.go) - -**Detection & Helpers:** -- `detect_unix.go` - Automatic detection for Linux/FreeBSD -- `detect_darwin.go` - Automatic detection for macOS -- `detect_windows.go` - Automatic detection for Windows - -**Documentation:** -- `README.md` - Comprehensive module documentation -- `examples/example_usage.go` - Usage examples for all platforms - -### Files Removed - -**Old NetBird-specific files:** -- `dbus_unix.go` - D-Bus utilities (functionality moved into platform-specific files) -- `file_parser_unix.go` - resolv.conf parser (simplified and integrated into file.go) -- `file_repair_unix.go` - File watching/repair (removed - out of scope) -- `file_unix.go` - Old file configurator (replaced by file.go) -- `host_darwin.go` - Old macOS configurator (replaced by darwin.go) -- `host_unix.go` - Old Unix manager factory (replaced by detect_unix.go) -- `host_windows.go` - Old Windows configurator (replaced by windows.go) -- `network_manager_unix.go` - Old NetworkManager (replaced by networkmanager.go) -- `resolvconf_unix.go` - Old resolvconf (replaced by resolvconf.go) -- `systemd_linux.go` - Old systemd-resolved (replaced by systemd.go) -- `unclean_shutdown_*.go` - Unclean shutdown detection (removed - out of scope) - -### Key Architectural Changes - -1. **Removed Build Tags for Platform Selection** - - Old: Used `//go:build` tags at top of files to compile different code per platform - - New: Named structs differently per platform (e.g., `DarwinDNSConfigurator`, `WindowsDNSConfigurator`) - - Build tags kept only where necessary for cross-platform library imports - -2. **Simplified Interface** - - Removed complex domain routing, search domains, and port customization - - Focused on core functionality: Set DNS, Get DNS, Restore DNS - - Removed state manager dependencies - -3. **Removed External Dependencies** - - Removed: statemanager, NetBird-specific types, logging libraries - - Kept only: D-Bus (for Linux), x/sys (for Windows registry and Unix syscalls) - - Uses standard library where possible - -4. **Standalone Operation** - - No longer depends on NetBird types (HostDNSConfig, etc.) - - Uses standard library types (net/netip.Addr) - - Self-contained backup/restore logic - -5. **Improved Code Organization** - - Each platform has its own clearly-named file - - Detection logic separated into detect_*.go files - - Shared types in types.go - - Examples in dedicated examples/ directory - -### Feature Comparison - -**Removed (out of scope for basic DNS override):** -- Search domain management -- Match-only domains -- DNS port customization (except where natively supported) -- File watching and auto-repair -- Unclean shutdown detection -- State persistence -- Integration with external state managers - -**Retained (core DNS functionality):** -- Setting DNS servers -- Getting current DNS servers -- Restoring original DNS servers -- Automatic platform detection -- DNS cache flushing -- Backup and restore of original configuration - -### Platform-Specific Notes - -**macOS (Darwin):** -- Simplified to focus on DNS server override using scutil -- Removed complex domain routing and local DNS setup -- Removed GPO and state management -- Kept DNS cache flushing - -**Windows:** -- Simplified registry manipulation to just NameServer key -- Removed NRPT (Name Resolution Policy Table) support -- Removed DNS registration and WINS management -- Kept DNS cache flushing - -**Linux - File-based:** -- Direct /etc/resolv.conf manipulation with backup -- Removed file watching and auto-repair -- Removed complex search domain merging logic -- Simple nameserver-only configuration - -**Linux - systemd-resolved:** -- D-Bus API for per-link DNS configuration -- Simplified to just DNS server setting -- Uses Revert method for restoration - -**Linux - NetworkManager:** -- D-Bus API for connection settings modification -- Simplified to IPv4 DNS only -- Removed search/match domain complexity - -**Linux - resolvconf:** -- Uses resolvconf utility (openresolv or Debian resolvconf) -- Interface-specific configuration -- Simple nameserver configuration - -### Usage Pattern - -```go -// Automatic detection -configurator, err := platform.DetectBestConfigurator("eth0") - -// Set DNS -original, err := configurator.SetDNS([]netip.Addr{ - netip.MustParseAddr("8.8.8.8"), -}) - -// Restore -defer configurator.RestoreDNS() -``` - -### Maintenance Notes - -- Each platform implementation is independent -- No shared state between configurators -- Backups are file-based or in-memory only -- No external database or state management required -- Configurators can be tested independently - -## Migration Guide - -If you were using the old code: - -1. Replace `HostDNSConfig` with simple `[]netip.Addr` for DNS servers -2. Replace `newHostManager()` with `platform.DetectBestConfigurator()` -3. Replace `applyDNSConfig()` with `SetDNS()` -4. Replace `restoreHostDNS()` with `RestoreDNS()` -5. Remove state manager dependencies -6. Remove search domain configuration (can be added back if needed) - -## Dependencies - -Required: -- `github.com/godbus/dbus/v5` - For Linux D-Bus configurators -- `golang.org/x/sys` - For Windows registry and Unix syscalls -- Standard library - -## Testing Recommendations - -Each configurator should be tested on its target platform: -- macOS: Test darwin.go with scutil -- Windows: Test windows.go with actual interface GUID -- Linux: Test all variants (file, systemd, networkmanager, resolvconf) -- Verify backup/restore functionality -- Test with invalid input (empty servers, bad interface names) diff --git a/dns/platform/examples/example_usage.go b/dns/platform/examples/example_usage.go deleted file mode 100644 index 7ae331f..0000000 --- a/dns/platform/examples/example_usage.go +++ /dev/null @@ -1,236 +0,0 @@ -package main - -import ( - "fmt" - "log" - "net/netip" - "os" - "os/signal" - "syscall" - "time" - - "github.com/your-org/olm/dns/platform" -) - -func main() { - // Example 1: Automatic detection and DNS override - exampleAutoDetection() - - // Example 2: Manual platform selection - // exampleManualSelection() - - // Example 3: Get current system DNS - // exampleGetCurrentDNS() -} - -// exampleAutoDetection demonstrates automatic detection of the best DNS configurator -func exampleAutoDetection() { - fmt.Println("=== Example 1: Automatic Detection ===") - - // On Linux/Unix, provide an interface name for better detection - // On macOS, the interface name is ignored - // On Windows, provide the interface GUID - ifaceName := "eth0" // Change this to your interface name - - configurator, err := platform.DetectBestConfigurator(ifaceName) - if err != nil { - log.Fatalf("Failed to detect DNS configurator: %v", err) - } - - fmt.Printf("Using DNS configurator: %s\n", configurator.Name()) - - // Get current DNS servers before changing - currentDNS, err := configurator.GetCurrentDNS() - if err != nil { - log.Printf("Warning: Could not get current DNS: %v", err) - } else { - fmt.Printf("Current DNS servers: %v\n", currentDNS) - } - - // Set new DNS servers - newDNS := []netip.Addr{ - netip.MustParseAddr("1.1.1.1"), // Cloudflare - netip.MustParseAddr("8.8.8.8"), // Google - } - - fmt.Printf("Setting DNS servers to: %v\n", newDNS) - originalDNS, err := configurator.SetDNS(newDNS) - if err != nil { - log.Fatalf("Failed to set DNS: %v", err) - } - - fmt.Printf("Original DNS servers (backed up): %v\n", originalDNS) - - // Set up signal handling for graceful shutdown - sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) - - // Run for 30 seconds or until interrupted - fmt.Println("\nDNS override active. Press Ctrl+C to restore original DNS.") - fmt.Println("Waiting 30 seconds...") - - select { - case <-time.After(30 * time.Second): - fmt.Println("\nTimeout reached.") - case sig := <-sigChan: - fmt.Printf("\nReceived signal: %v\n", sig) - } - - // Restore original DNS - fmt.Println("Restoring original DNS servers...") - if err := configurator.RestoreDNS(); err != nil { - log.Fatalf("Failed to restore DNS: %v", err) - } - - fmt.Println("DNS restored successfully!") -} - -// exampleManualSelection demonstrates manual selection of DNS configurator -func exampleManualSelection() { - fmt.Println("=== Example 2: Manual Selection ===") - - // Linux - systemd-resolved - configurator, err := platform.NewSystemdResolvedDNSConfigurator("eth0") - if err != nil { - log.Fatalf("Failed to create systemd-resolved configurator: %v", err) - } - - fmt.Printf("Using: %s\n", configurator.Name()) - - newDNS := []netip.Addr{ - netip.MustParseAddr("1.1.1.1"), - } - - originalDNS, err := configurator.SetDNS(newDNS) - if err != nil { - log.Fatalf("Failed to set DNS: %v", err) - } - - fmt.Printf("Changed from %v to %v\n", originalDNS, newDNS) - - // Restore after 10 seconds - time.Sleep(10 * time.Second) - configurator.RestoreDNS() -} - -// exampleGetCurrentDNS demonstrates getting current system DNS -func exampleGetCurrentDNS() { - fmt.Println("=== Example 3: Get Current DNS ===") - - configurator, err := platform.DetectBestConfigurator("eth0") - if err != nil { - log.Fatalf("Failed to detect configurator: %v", err) - } - - servers, err := configurator.GetCurrentDNS() - if err != nil { - log.Fatalf("Failed to get DNS: %v", err) - } - - fmt.Printf("Current DNS servers (%s):\n", configurator.Name()) - for i, server := range servers { - fmt.Printf(" %d. %s\n", i+1, server) - } -} - -// Platform-specific examples - -// exampleLinuxFile demonstrates direct file manipulation on Linux -func exampleLinuxFile() { - configurator, err := platform.NewFileDNSConfigurator() - if err != nil { - log.Fatal(err) - } - - newDNS := []netip.Addr{ - netip.MustParseAddr("8.8.8.8"), - } - - originalDNS, err := configurator.SetDNS(newDNS) - if err != nil { - log.Fatal(err) - } - - defer configurator.RestoreDNS() - - fmt.Printf("Changed from %v to %v\n", originalDNS, newDNS) - time.Sleep(10 * time.Second) -} - -// exampleLinuxNetworkManager demonstrates NetworkManager on Linux -func exampleLinuxNetworkManager() { - if !platform.IsNetworkManagerAvailable() { - fmt.Println("NetworkManager is not available") - return - } - - configurator, err := platform.NewNetworkManagerDNSConfigurator("eth0") - if err != nil { - log.Fatal(err) - } - - newDNS := []netip.Addr{ - netip.MustParseAddr("1.1.1.1"), - } - - originalDNS, err := configurator.SetDNS(newDNS) - if err != nil { - log.Fatal(err) - } - - defer configurator.RestoreDNS() - - fmt.Printf("Changed from %v to %v\n", originalDNS, newDNS) - time.Sleep(10 * time.Second) -} - -// exampleMacOS demonstrates macOS DNS override -func exampleMacOS() { - configurator, err := platform.NewDarwinDNSConfigurator() - if err != nil { - log.Fatal(err) - } - - newDNS := []netip.Addr{ - netip.MustParseAddr("1.1.1.1"), - netip.MustParseAddr("1.0.0.1"), - } - - originalDNS, err := configurator.SetDNS(newDNS) - if err != nil { - log.Fatal(err) - } - - defer configurator.RestoreDNS() - - fmt.Printf("Changed from %v to %v\n", originalDNS, newDNS) - time.Sleep(10 * time.Second) -} - -// exampleWindows demonstrates Windows DNS override -func exampleWindows() { - // You need to get the interface GUID first - // This can be obtained from: - // - ipconfig /all (look for the interface's GUID) - // - registry: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces - guid := "{YOUR-INTERFACE-GUID-HERE}" - - configurator, err := platform.NewWindowsDNSConfigurator(guid) - if err != nil { - log.Fatal(err) - } - - newDNS := []netip.Addr{ - netip.MustParseAddr("1.1.1.1"), - } - - originalDNS, err := configurator.SetDNS(newDNS) - if err != nil { - log.Fatal(err) - } - - defer configurator.RestoreDNS() - - fmt.Printf("Changed from %v to %v\n", originalDNS, newDNS) - time.Sleep(10 * time.Second) -}