Files
elmprodvpn/selective-vpn-api/app/smartdns_runtime_config.go

117 lines
2.8 KiB
Go

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
}