package vpn import ( "os" "strings" "testing" ) func TestParseIPRangeAndFirstAvailable(t *testing.T) { start, end, err := parseIPRange("192.168.133.2-192.168.133.254") if err != nil { t.Fatalf("unexpected error parsing range: %v", err) } if start.String() != "192.168.133.2" || end.String() != "192.168.133.254" { t.Fatalf("unexpected parsed range: %s - %s", start, end) } used := map[string]bool{ "192.168.133.2": true, "192.168.133.3": true, } first := firstAvailableIPFromRange("192.168.133.2-192.168.133.254", used) if first != "192.168.133.4" { t.Fatalf("expected 192.168.133.4, got %s", first) } } func TestSyncSecretsInheritanceAndOverrides(t *testing.T) { tmpDir, err := os.MkdirTemp("", "ppp-test-*") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpDir) mgr := &PPPServerManager{ baseDir: tmpDir, profiles: make(map[string]*PPPProfile), secrets: make(map[string]*PPPSecret), } mgr.initDefaults() // Add custom profile with range mgr.profiles["p2p"] = &PPPProfile{ ID: "p2p", Name: "p2p", LocalAddress: "192.168.133.1", RemoteAddress: "192.168.133.2-192.168.133.254", } // Add profile with single static IP mgr.profiles["static-prof"] = &PPPProfile{ ID: "static-prof", Name: "static-prof", LocalAddress: "10.200.1.1", RemoteAddress: "10.200.1.50", } // Secret 1: explicit override on secret mgr.secrets["s1"] = &PPPSecret{ ID: "s1", Name: "user_explicit", Password: "pass1", Profile: "p2p", RemoteAddress: "192.168.133.99", } // Secret 2: inherits from range profile mgr.secrets["s2"] = &PPPSecret{ ID: "s2", Name: "user_range_inherit", Password: "pass2", Profile: "p2p", } // Secret 3: inherits from single static IP profile mgr.secrets["s3"] = &PPPSecret{ ID: "s3", Name: "user_static_inherit", Password: "pass3", Profile: "static-prof", } // Secret 4: default profile range inherit mgr.secrets["s4"] = &PPPSecret{ ID: "s4", Name: "user_default_inherit", Password: "pass4", Profile: "default", } if err := mgr.syncSecretsToSystemLocked(); err != nil { t.Fatalf("sync error: %v", err) } data, err := os.ReadFile("/etc/ppp/chap-secrets") if err != nil { t.Skip("skipping chap-secrets read if no root permission") } content := string(data) // Verify user_explicit got 192.168.133.99 if !strings.Contains(content, "\"user_explicit\"\t*\t\"pass1\"\t192.168.133.99") { t.Errorf("user_explicit expected 192.168.133.99 in chap-secrets, got:\n%s", content) } // Verify user_static_inherit got 10.200.1.50 if !strings.Contains(content, "\"user_static_inherit\"\t*\t\"pass3\"\t10.200.1.50") { t.Errorf("user_static_inherit expected 10.200.1.50 in chap-secrets, got:\n%s", content) } // Verify user_range_inherit got first available from p2p (192.168.133.2) if !strings.Contains(content, "\"user_range_inherit\"\t*\t\"pass2\"\t192.168.133.2") { t.Errorf("user_range_inherit expected 192.168.133.2 in chap-secrets, got:\n%s", content) } }