package sandbox import ( "encoding/json" "fmt" "net" "net/url" "strconv" "strings" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/iwind/TeaGo/maps" ) type TestAction struct { actionutils.ParentAction } func (this *TestAction) RunPost(params struct { AppId string Domain string ClientIp string Qtype string SDNSParamsJSON string }) { if len(params.ClientIp) == 0 { params.ClientIp = "203.0.113.100" } params.SDNSParamsJSON = strings.TrimSpace(params.SDNSParamsJSON) sdnsParams, err := parseSDNSParamsJSON(params.SDNSParamsJSON) if err != nil { this.Fail(err.Error()) return } clientSubnet := this.maskSubnet(params.ClientIp, 24, 56) if len(clientSubnet) == 0 { clientSubnet = "203.0.113.0/24" } sniPolicy := "empty" publicSNI := "" ecsMode := "off" ecsIPv4Prefix := 24 ecsIPv6Prefix := 56 pinningMode := "off" sanMode := "off" query := url.Values{} query.Set("appId", params.AppId) query.Set("dn", params.Domain) query.Set("cip", params.ClientIp) query.Set("qtype", params.Qtype) for _, item := range sdnsParams { query.Add("sdns_"+item.GetString("name"), item.GetString("value")) } requestURL := "https://api.httpdns.example.com/resolve?" + query.Encode() this.Data["result"] = maps.Map{ "code": 0, "message": "ok (mock)", "requestId": "mock-rid-20260221-001", "data": maps.Map{ "request_url": requestURL, "client_ip": params.ClientIp, "client_region": "中国, 上海, 上海", "line_name": "默认线路", "sdns_params": sdnsParams, "ips": []string{"203.0.113.10", "203.0.113.11"}, "records": []maps.Map{ { "domain": params.Domain, "type": params.Qtype, "ip": "203.0.113.10", "ttl": 30, "region": "中国-上海-上海", "line": "默认线路", }, { "domain": params.Domain, "type": params.Qtype, "ip": "203.0.113.11", "ttl": 30, "region": "中国-上海-上海", "line": "默认线路", }, }, "ttl": 30, "sni_policy": sniPolicy, "public_sni": publicSNI, "client_subnet": clientSubnet, "ecs_mode": ecsMode, "ecs_ipv4_prefix": ecsIPv4Prefix, "ecs_ipv6_prefix": ecsIPv6Prefix, "pinning_mode": pinningMode, "san_mode": sanMode, "fingerprint_algo": "sha256", "cert_fingerprints": []string{"8f41ab8d32fca7f9a2b0fdd09a0e2ccf31e5579cd3a0b65f1a9f2f2ec8f38d4a"}, "verify_headers": maps.Map{ "X-Edge-Resolve-AppId": params.AppId, "X-Edge-Resolve-Expire": "1768953600", "X-Edge-Resolve-Nonce": "mock-nonce-123456", "X-Edge-Resolve-Target": params.Domain, "X-Edge-Resolve-Sign": "mock-signature-base64url", }, }, } this.Success() } func parseSDNSParamsJSON(raw string) ([]maps.Map, error) { if len(raw) == 0 { return []maps.Map{}, nil } list := []maps.Map{} if err := json.Unmarshal([]byte(raw), &list); err != nil { return nil, err } if len(list) > 10 { return nil, fmt.Errorf("sdns params should be <= 10") } result := make([]maps.Map, 0, len(list)) for _, item := range list { name := strings.TrimSpace(item.GetString("name")) value := strings.TrimSpace(item.GetString("value")) if len(name) == 0 && len(value) == 0 { continue } if len(name) == 0 || len(name) > 64 { return nil, fmt.Errorf("sdns param name should be in 1-64") } if len(value) == 0 || len(value) > 64 { return nil, fmt.Errorf("sdns param value should be in 1-64") } result = append(result, maps.Map{ "name": name, "value": value, }) } if len(result) > 10 { return nil, fmt.Errorf("sdns params should be <= 10") } return result, nil } func (this *TestAction) maskSubnet(ip string, ipv4Prefix int, ipv6Prefix int) string { parsed := net.ParseIP(ip) if parsed == nil { return "" } ipv4 := parsed.To4() if ipv4 != nil { mask := net.CIDRMask(ipv4Prefix, 32) return ipv4.Mask(mask).String() + "/" + strconv.Itoa(ipv4Prefix) } mask := net.CIDRMask(ipv6Prefix, 128) return parsed.Mask(mask).String() + "/" + strconv.Itoa(ipv6Prefix) }