package app import ( "os" "strings" ) func smartDNSRuntimeEnabledFromConfig() (bool, error) { data, err := os.ReadFile(smartdnsMainConfig) if err != nil { return false, err } for _, raw := range strings.Split(string(data), "\n") { trimmed := strings.TrimSpace(raw) if trimmed == "" || strings.HasPrefix(trimmed, "#") { continue } if strings.Contains(trimmed, "nftset") && strings.Contains(trimmed, "domain-set:agvpn_wild") && strings.Contains(trimmed, "agvpn_dyn4") { return true, nil } } return false, nil } func normalizeSmartDNSMainConfig(content string, enabled bool) string { normalized := strings.ReplaceAll(content, "\r\n", "\n") lines := strings.Split(normalized, "\n") out := make([]string, 0, len(lines)+4) seenDomain := false seenNftset := false isDomainLine := func(raw string) bool { t := strings.TrimSpace(raw) if strings.HasPrefix(t, "#") { t = strings.TrimSpace(strings.TrimPrefix(t, "#")) } return strings.HasPrefix(t, "domain-set ") && strings.Contains(t, "-name agvpn_wild") && strings.Contains(t, "/etc/selective-vpn/smartdns.conf") } isNftsetLine := func(raw string) bool { t := strings.TrimSpace(raw) if strings.HasPrefix(t, "#") { t = strings.TrimSpace(strings.TrimPrefix(t, "#")) } return strings.HasPrefix(t, "nftset ") && strings.Contains(t, "domain-set:agvpn_wild") && strings.Contains(t, "agvpn_dyn4") } for _, raw := range lines { switch { case isDomainLine(raw): if !seenDomain { if enabled { out = append(out, smartdnsRuntimeDomainSetLine) } else { out = append(out, "# "+smartdnsRuntimeDomainSetLine) } seenDomain = true } case isNftsetLine(raw): if !seenNftset { if enabled { out = append(out, smartdnsRuntimeNftsetLine) } else { out = append(out, "# "+smartdnsRuntimeNftsetLine) } seenNftset = true } default: out = append(out, raw) } } if enabled && (!seenDomain || !seenNftset) { if len(out) > 0 && strings.TrimSpace(out[len(out)-1]) != "" { out = append(out, "") } if !seenDomain { out = append(out, smartdnsRuntimeDomainSetLine) } if !seenNftset { out = append(out, smartdnsRuntimeNftsetLine) } } rendered := strings.Join(out, "\n") if !strings.HasSuffix(rendered, "\n") { rendered += "\n" } return rendered } func applySmartDNSRuntimeConfig(enabled bool) (bool, error) { data, err := os.ReadFile(smartdnsMainConfig) if err != nil { return false, err } current := strings.ReplaceAll(string(data), "\r\n", "\n") next := normalizeSmartDNSMainConfig(current, enabled) if next == current { return false, nil } tmp := smartdnsMainConfig + ".tmp" if err := os.WriteFile(tmp, []byte(next), 0o644); err != nil { return false, err } if err := os.Rename(tmp, smartdnsMainConfig); err != nil { return false, err } return true, nil }