Harden resolver and expand traffic runtime controls
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -42,9 +43,24 @@ func handleDomainsTable(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
stdout, _, _, err := runCommand("ipset", "list", "agvpn4")
|
||||
lines := []string{}
|
||||
if err == nil {
|
||||
for _, setName := range []string{"agvpn4", "agvpn_dyn4"} {
|
||||
stdout, _, code, _ := runCommand("nft", "list", "set", "inet", "agvpn", setName)
|
||||
if code == 0 {
|
||||
for _, l := range strings.Split(stdout, "\n") {
|
||||
l = strings.TrimRight(l, "\r")
|
||||
if l != "" {
|
||||
lines = append(lines, l)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Backward-compatible fallback for legacy hosts that still have ipset.
|
||||
stdout, _, code, _ = runCommand("ipset", "list", setName)
|
||||
if code != 0 {
|
||||
continue
|
||||
}
|
||||
for _, l := range strings.Split(stdout, "\n") {
|
||||
l = strings.TrimRight(l, "\r")
|
||||
if l != "" {
|
||||
@@ -59,7 +75,7 @@ func handleDomainsTable(w http.ResponseWriter, r *http.Request) {
|
||||
// domains file
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// GET /api/v1/domains/file?name=bases|meta|subs|static|smartdns|last-ips-map|last-ips-map-direct|last-ips-map-wildcard
|
||||
// GET /api/v1/domains/file?name=bases|meta|subs|static|smartdns|last-ips-map|last-ips-map-direct|last-ips-map-wildcard|wildcard-observed-hosts
|
||||
// POST /api/v1/domains/file { "name": "...", "content": "..." }
|
||||
func handleDomainsFile(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
@@ -73,6 +89,13 @@ func handleDomainsFile(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
return
|
||||
}
|
||||
if name == "wildcard-observed-hosts" {
|
||||
writeJSON(w, http.StatusOK, map[string]string{
|
||||
"content": readWildcardObservedHostsContent(),
|
||||
"source": "derived",
|
||||
})
|
||||
return
|
||||
}
|
||||
path, ok := domainFiles[name]
|
||||
if !ok {
|
||||
http.Error(w, "unknown file name", http.StatusBadRequest)
|
||||
@@ -126,7 +149,7 @@ func handleDomainsFile(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
|
||||
return
|
||||
}
|
||||
if body.Name == "last-ips-map-direct" || body.Name == "last-ips-map-wildcard" {
|
||||
if body.Name == "last-ips-map-direct" || body.Name == "last-ips-map-wildcard" || body.Name == "wildcard-observed-hosts" {
|
||||
http.Error(w, "read-only file name", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
@@ -146,6 +169,39 @@ func handleDomainsFile(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func readWildcardObservedHostsContent() string {
|
||||
data, err := os.ReadFile(lastIPsMapDyn)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
seen := make(map[string]struct{})
|
||||
out := make([]string, 0, 256)
|
||||
for _, ln := range strings.Split(string(data), "\n") {
|
||||
ln = strings.TrimSpace(ln)
|
||||
if ln == "" || strings.HasPrefix(ln, "#") {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(ln)
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
host := strings.TrimSpace(fields[1])
|
||||
if host == "" || strings.HasPrefix(host, "[") {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[host]; ok {
|
||||
continue
|
||||
}
|
||||
seen[host] = struct{}{}
|
||||
out = append(out, host)
|
||||
}
|
||||
sort.Strings(out)
|
||||
if len(out) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.Join(out, "\n") + "\n"
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// smartdns wildcards
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user