platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
139
selective-vpn-api/app/resolver/static_labels.go
Normal file
139
selective-vpn-api/app/resolver/static_labels.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ParseStaticEntries(lines []string, logf func(string, ...any)) (entries [][3]string, skipped int) {
|
||||
for _, ln := range lines {
|
||||
s := strings.TrimSpace(ln)
|
||||
if s == "" || strings.HasPrefix(s, "#") {
|
||||
continue
|
||||
}
|
||||
comment := ""
|
||||
if idx := strings.Index(s, "#"); idx >= 0 {
|
||||
comment = strings.TrimSpace(s[idx+1:])
|
||||
s = strings.TrimSpace(s[:idx])
|
||||
}
|
||||
if s == "" || IsPrivateIPv4(s) {
|
||||
continue
|
||||
}
|
||||
|
||||
rawBase := strings.SplitN(s, "/", 2)[0]
|
||||
if strings.Contains(s, "/") {
|
||||
if _, err := netip.ParsePrefix(s); err != nil {
|
||||
skipped++
|
||||
if logf != nil {
|
||||
logf("static skip invalid prefix %q: %v", s, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if _, err := netip.ParseAddr(rawBase); err != nil {
|
||||
skipped++
|
||||
if logf != nil {
|
||||
logf("static skip invalid ip %q: %v", s, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
entries = append(entries, [3]string{s, rawBase, comment})
|
||||
}
|
||||
return entries, skipped
|
||||
}
|
||||
|
||||
func ResolveStaticLabels(entries [][3]string, dnsForPtr string, ptrCache map[string]any, ttl int, logf func(string, ...any)) (map[string][]string, int, int) {
|
||||
now := int(time.Now().Unix())
|
||||
result := map[string][]string{}
|
||||
ptrLookups := 0
|
||||
ptrErrors := 0
|
||||
|
||||
for _, e := range entries {
|
||||
ipEntry, baseIP, comment := e[0], e[1], e[2]
|
||||
var labels []string
|
||||
if comment != "" {
|
||||
labels = append(labels, "*"+comment)
|
||||
}
|
||||
if comment == "" {
|
||||
if cached, ok := ptrCache[baseIP].(map[string]any); ok {
|
||||
names, _ := cached["names"].([]any)
|
||||
last, _ := cached["last_resolved"].(float64)
|
||||
if len(names) > 0 && last > 0 && now-int(last) <= ttl {
|
||||
for _, n := range names {
|
||||
if s, ok := n.(string); ok && s != "" {
|
||||
labels = append(labels, "*"+s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(labels) == 0 {
|
||||
ptrLookups++
|
||||
names, err := DigPTR(baseIP, dnsForPtr, 3*time.Second, logf)
|
||||
if err != nil {
|
||||
ptrErrors++
|
||||
}
|
||||
if len(names) > 0 {
|
||||
ptrCache[baseIP] = map[string]any{"names": names, "last_resolved": now}
|
||||
for _, n := range names {
|
||||
labels = append(labels, "*"+n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(labels) == 0 {
|
||||
labels = []string{"*[STATIC-IP]"}
|
||||
}
|
||||
result[ipEntry] = labels
|
||||
if logf != nil {
|
||||
logf("static %s -> %v", ipEntry, labels)
|
||||
}
|
||||
}
|
||||
|
||||
return result, ptrLookups, ptrErrors
|
||||
}
|
||||
|
||||
func DigPTR(ip, upstream string, timeout time.Duration, logf func(string, ...any)) ([]string, error) {
|
||||
server, port := SplitDNS(upstream)
|
||||
if server == "" {
|
||||
return nil, fmt.Errorf("upstream empty")
|
||||
}
|
||||
if port == "" {
|
||||
port = "53"
|
||||
}
|
||||
addr := net.JoinHostPort(server, port)
|
||||
r := &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
d := net.Dialer{}
|
||||
return d.DialContext(ctx, "udp", addr)
|
||||
},
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
names, err := r.LookupAddr(ctx, ip)
|
||||
cancel()
|
||||
if err != nil {
|
||||
if logf != nil {
|
||||
logf("ptr error %s via %s: %v", ip, addr, err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
seen := map[string]struct{}{}
|
||||
var out []string
|
||||
for _, n := range names {
|
||||
n = strings.TrimSuffix(strings.ToLower(strings.TrimSpace(n)), ".")
|
||||
if n == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[n]; !ok {
|
||||
seen[n] = struct{}{}
|
||||
out = append(out, n)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
Reference in New Issue
Block a user