package sandbox import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "net/url" "strconv" "strings" "time" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/index/loginutils" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/rands" ) type TestAction struct { actionutils.ParentAction } func (this *TestAction) RunPost(params struct { AppId string ClusterId int64 Domain string ClientIp string Qtype string }) { clientIP := strings.TrimSpace(params.ClientIp) if len(clientIP) == 0 { clientIP = strings.TrimSpace(loginutils.RemoteIP(&this.ActionObject)) } qtype := strings.ToUpper(strings.TrimSpace(params.Qtype)) if len(qtype) == 0 { qtype = "A" } resp, err := this.RPC().HTTPDNSSandboxRPC().TestHTTPDNSResolve(this.AdminContext(), &pb.TestHTTPDNSResolveRequest{ ClusterId: params.ClusterId, AppId: strings.TrimSpace(params.AppId), Domain: strings.TrimSpace(params.Domain), Qtype: qtype, ClientIP: clientIP, Sid: "", SdkVersion: "", Os: "", }) if err != nil { this.ErrorPage(err) return } clusterDomain := "" port := "443" if params.ClusterId > 0 { clusterResp, findErr := this.RPC().HTTPDNSClusterRPC().FindHTTPDNSCluster(this.AdminContext(), &pb.FindHTTPDNSClusterRequest{ ClusterId: params.ClusterId, }) if findErr == nil && clusterResp.GetCluster() != nil { clusterDomain = strings.TrimSpace(clusterResp.GetCluster().GetServiceDomain()) if rawTLS := clusterResp.GetCluster().GetTlsPolicyJSON(); len(rawTLS) > 0 { var tlsConfig map[string]interface{} if err := json.Unmarshal(rawTLS, &tlsConfig); err == nil { if listenRaw, ok := tlsConfig["listen"]; ok && listenRaw != nil { if data, err := json.Marshal(listenRaw); err == nil { var listenAddresses []map[string]interface{} if err := json.Unmarshal(data, &listenAddresses); err == nil { if len(listenAddresses) > 0 { if portRange, ok := listenAddresses[0]["portRange"].(string); ok && len(portRange) > 0 { port = portRange } } } } } } } } } if len(clusterDomain) == 0 { clusterDomain = "httpdns.example.com" } query := url.Values{} query.Set("appId", params.AppId) query.Set("dn", params.Domain) query.Set("qtype", qtype) if len(clientIP) > 0 { query.Set("cip", clientIP) } signEnabled, signSecret := this.findAppSignConfig(params.AppId) if signEnabled && len(signSecret) > 0 { exp := strconv.FormatInt(time.Now().Unix()+300, 10) nonce := "sandbox-" + rands.HexString(16) sign := buildSandboxResolveSign(signSecret, params.AppId, params.Domain, qtype, exp, nonce) query.Set("exp", exp) query.Set("nonce", nonce) query.Set("sign", sign) } requestURL := "https://" + clusterDomain + ":" + port + "/resolve?" + query.Encode() resultCode := 1 if strings.EqualFold(resp.GetCode(), "SUCCESS") { resultCode = 0 } rows := make([]maps.Map, 0, len(resp.GetRecords())) ips := make([]string, 0, len(resp.GetRecords())) lineName := strings.TrimSpace(resp.GetClientCarrier()) if len(lineName) == 0 { lineName = "-" } for _, record := range resp.GetRecords() { ips = append(ips, record.GetIp()) if lineName == "-" && len(record.GetLine()) > 0 { lineName = record.GetLine() } rows = append(rows, maps.Map{ "domain": resp.GetDomain(), "type": record.GetType(), "ip": record.GetIp(), "ttl": record.GetTtl(), "region": record.GetRegion(), "line": record.GetLine(), }) } this.Data["result"] = maps.Map{ "code": resultCode, "message": resp.GetMessage(), "requestId": resp.GetRequestId(), "data": maps.Map{ "request_url": requestURL, "client_ip": resp.GetClientIP(), "client_region": resp.GetClientRegion(), "line_name": lineName, "ips": ips, "records": rows, "ttl": resp.GetTtl(), }, } this.Success() } func (this *TestAction) findAppSignConfig(appId string) (bool, string) { appId = strings.TrimSpace(appId) if len(appId) == 0 { return false, "" } resp, err := this.RPC().HTTPDNSAppRPC().FindAllHTTPDNSApps(this.AdminContext(), &pb.FindAllHTTPDNSAppsRequest{}) if err != nil { return false, "" } for _, app := range resp.GetApps() { if strings.EqualFold(strings.TrimSpace(app.GetAppId()), appId) { return app.GetSignEnabled(), strings.TrimSpace(app.GetSignSecret()) } } return false, "" } func buildSandboxResolveSign(signSecret string, appID string, domain string, qtype string, exp string, nonce string) string { raw := strings.TrimSpace(appID) + "|" + strings.ToLower(strings.TrimSpace(domain)) + "|" + strings.ToUpper(strings.TrimSpace(qtype)) + "|" + strings.TrimSpace(exp) + "|" + strings.TrimSpace(nonce) mac := hmac.New(sha256.New, []byte(strings.TrimSpace(signSecret))) _, _ = mac.Write([]byte(raw)) return hex.EncodeToString(mac.Sum(nil)) }