166 lines
4.5 KiB
Go
166 lines
4.5 KiB
Go
package app
|
|
|
|
import (
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// ---------------------------------------------------------------------
|
|
// EN: `loadList` loads list from storage or config.
|
|
// RU: `loadList` - загружает list из хранилища или конфига.
|
|
// ---------------------------------------------------------------------
|
|
func loadList(path string) []string {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
var out []string
|
|
for _, ln := range strings.Split(string(data), "\n") {
|
|
ln = strings.TrimSpace(strings.SplitN(ln, "#", 2)[0])
|
|
if ln == "" {
|
|
continue
|
|
}
|
|
out = append(out, ln)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// EN: `loadSmartDNSWildcardDomains` loads SmartDNS wildcard domains from canonical API state.
|
|
// RU: `loadSmartDNSWildcardDomains` - загружает wildcard-домены SmartDNS из каноничного API-состояния.
|
|
// ---------------------------------------------------------------------
|
|
func loadSmartDNSWildcardDomains(logf func(string, ...any)) []string {
|
|
out, source := loadSmartDNSWildcardDomainsState(logf)
|
|
sort.Strings(out)
|
|
if logf != nil {
|
|
logf("smartdns wildcards loaded: source=%s count=%d", source, len(out))
|
|
}
|
|
return out
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// EN: `isGoogleLike` checks whether google like is true.
|
|
// RU: `isGoogleLike` - проверяет, является ли google like истинным условием.
|
|
// ---------------------------------------------------------------------
|
|
func isGoogleLike(d string) bool {
|
|
low := strings.ToLower(d)
|
|
for _, base := range googleLikeDomains {
|
|
if low == base || strings.HasSuffix(low, "."+base) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// EN: `readNonEmptyLines` reads non empty lines from input data.
|
|
// RU: `readNonEmptyLines` - читает non empty lines из входных данных.
|
|
// ---------------------------------------------------------------------
|
|
func readNonEmptyLines(path string) []string {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
var out []string
|
|
for _, ln := range strings.Split(string(data), "\n") {
|
|
ln = strings.TrimSpace(ln)
|
|
if ln != "" {
|
|
out = append(out, ln)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func writeLines(path string, lines []string) error {
|
|
if len(lines) == 0 {
|
|
return os.WriteFile(path, []byte{}, 0o644)
|
|
}
|
|
return os.WriteFile(path, []byte(strings.Join(lines, "\n")+"\n"), 0o644)
|
|
}
|
|
|
|
func writeMapPairs(path string, pairs [][2]string) error {
|
|
if len(pairs) == 0 {
|
|
return os.WriteFile(path, []byte{}, 0o644)
|
|
}
|
|
lines := make([]string, 0, len(pairs))
|
|
for _, p := range pairs {
|
|
lines = append(lines, p[0]+"\t"+p[1])
|
|
}
|
|
return os.WriteFile(path, []byte(strings.Join(lines, "\n")+"\n"), 0o644)
|
|
}
|
|
|
|
func countDomainsFromPairs(pairs [][2]string) int {
|
|
seen := make(map[string]struct{})
|
|
for _, p := range pairs {
|
|
if len(p) < 2 {
|
|
continue
|
|
}
|
|
d := strings.TrimSpace(p[1])
|
|
if d == "" || strings.HasPrefix(d, "[") {
|
|
continue
|
|
}
|
|
seen[d] = struct{}{}
|
|
}
|
|
return len(seen)
|
|
}
|
|
|
|
func wildcardHostIPMap(pairs [][2]string) map[string][]string {
|
|
hostToIPs := make(map[string]map[string]struct{})
|
|
for _, p := range pairs {
|
|
if len(p) < 2 {
|
|
continue
|
|
}
|
|
ip := strings.TrimSpace(p[0])
|
|
host := strings.TrimSpace(p[1])
|
|
if ip == "" || host == "" || strings.HasPrefix(host, "[") {
|
|
continue
|
|
}
|
|
ips := hostToIPs[host]
|
|
if ips == nil {
|
|
ips = map[string]struct{}{}
|
|
hostToIPs[host] = ips
|
|
}
|
|
ips[ip] = struct{}{}
|
|
}
|
|
|
|
out := make(map[string][]string, len(hostToIPs))
|
|
for host, ipset := range hostToIPs {
|
|
ips := make([]string, 0, len(ipset))
|
|
for ip := range ipset {
|
|
ips = append(ips, ip)
|
|
}
|
|
sort.Strings(ips)
|
|
out[host] = ips
|
|
}
|
|
return out
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// EN: `countDomainsFromMap` counts items for domains from map.
|
|
// RU: `countDomainsFromMap` - считает элементы для domains from map.
|
|
// ---------------------------------------------------------------------
|
|
func countDomainsFromMap(path string) int {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
seen := make(map[string]struct{})
|
|
for _, ln := range strings.Split(string(data), "\n") {
|
|
ln = strings.TrimSpace(ln)
|
|
if ln == "" {
|
|
continue
|
|
}
|
|
fields := strings.Fields(ln)
|
|
if len(fields) < 2 {
|
|
continue
|
|
}
|
|
d := fields[1]
|
|
if strings.HasPrefix(d, "[") {
|
|
continue
|
|
}
|
|
seen[d] = struct{}{}
|
|
}
|
|
return len(seen)
|
|
}
|