//go:build standalone package checker import ( "errors" "net/http" "strconv" "strings" sdk "git.happydns.org/checker-sdk-go/checker" ) func (p *resolverPropagationProvider) RenderForm() []sdk.CheckerOptionField { return []sdk.CheckerOptionField{ { Id: "domain_name", Type: "string", Label: "Zone name", Placeholder: "example.com", Required: true, Description: "Apex of the zone to probe across public resolvers.", }, { Id: "recordTypes", Type: "string", Label: "Record types to probe", Placeholder: "SOA,NS,A,AAAA,MX,TXT,CAA", Description: "Comma-separated list of RR types. Probed at the apex (and at each 'subdomains' entry).", }, { Id: "subdomains", Type: "string", Label: "Extra subdomains to probe", Placeholder: "www", Description: "Comma-separated list of owner names to probe in addition to the apex (e.g. \"www,mail,@\").", }, { Id: "includeFiltered", Type: "bool", Label: "Include filtered resolvers", Description: "Probe filtering resolvers (malware/family/adblock). Their answers routinely disagree with the consensus by design.", }, { Id: "region", Type: "string", Label: "Restrict to region", Placeholder: "all", Description: "One of: all, global, na, eu, asia, ru, me.", Choices: []string{"all", "global", "na", "eu", "asia", "ru", "me"}, }, { Id: "transports", Type: "string", Label: "Transports", Placeholder: "udp", Description: "Comma-separated list of transports to probe: udp, tcp, dot, doh.", }, { Id: "resolverAllowlist", Type: "string", Label: "Resolver allowlist (advanced)", Placeholder: "cloudflare,google,9.9.9.9", Description: "Comma-separated list of resolver IDs or IPs to probe exclusively. Leave empty to use the catalog selection.", }, { Id: "latencyThresholdMs", Type: "uint", Label: "Latency warning threshold (ms)", Placeholder: "500", Description: "Resolvers averaging above this value produce an info finding.", }, { Id: "runTimeoutSeconds", Type: "uint", Label: "Run timeout (seconds)", Placeholder: "30", Description: "Hard wall-clock budget for one propagation run.", }, } } func (p *resolverPropagationProvider) ParseForm(r *http.Request) (sdk.CheckerOptions, error) { name := strings.TrimSpace(r.FormValue("domain_name")) if name == "" { return nil, errors.New("domain_name is required") } name = strings.TrimSuffix(name, ".") opts := sdk.CheckerOptions{ "domain_name": name, } for _, key := range []string{ "recordTypes", "subdomains", "region", "transports", "resolverAllowlist", } { if v := strings.TrimSpace(r.FormValue(key)); v != "" { opts[key] = v } } if v := strings.TrimSpace(r.FormValue("includeFiltered")); v != "" { switch strings.ToLower(v) { case "1", "true", "on", "yes": opts["includeFiltered"] = true case "0", "false", "off", "no": opts["includeFiltered"] = false } } for _, key := range []string{"latencyThresholdMs", "runTimeoutSeconds"} { if v := strings.TrimSpace(r.FormValue(key)); v != "" { n, err := strconv.ParseUint(v, 10, 32) if err != nil { return nil, errors.New(key + " must be a non-negative integer") } opts[key] = float64(n) } } return opts, nil }