feat(ednsdiag): support custom DoH endpoint via --url

Allow overriding the provider preset with an explicit HTTPS DoH URL,
including validation that custom endpoints apply only to DoH queries.
This commit is contained in:
windyboy
2026-08-13 15:34:54 +08:00
parent 5b0f7950e6
commit 6f8a4918f0
3 changed files with 17 additions and 1 deletions
@@ -129,6 +129,8 @@ func parseQueryArgs(args []string) (edns.QueryOptions, time.Duration, error) {
options.Protocol = strings.ToLower(value) options.Protocol = strings.ToLower(value)
case "provider": case "provider":
options.Provider = strings.ToLower(value) options.Provider = strings.ToLower(value)
case "url":
options.EndpointURL = value
case "method": case "method":
options.Method = strings.ToLower(value) options.Method = strings.ToLower(value)
case "timeout": case "timeout":
@@ -178,5 +180,5 @@ func writeUsage(writer io.Writer) {
} }
func writeQueryUsage(writer io.Writer) { func writeQueryUsage(writer io.Writer) {
fmt.Fprintln(writer, "usage: ednsdiag query <domain> [type] [--protocol doh|dot] [--provider cloudflare|google|quad9|adguard] [--method post|get] [--timeout 5s]") fmt.Fprintln(writer, "usage: ednsdiag query <domain> [type] [--protocol doh|dot] [--provider cloudflare|google|quad9|adguard] [--url https://host/dns-query] [--method post|get] [--timeout 5s]")
} }
@@ -6,6 +6,7 @@ type QueryOptions struct {
Protocol string Protocol string
Provider string Provider string
Method string Method string
EndpointURL string
} }
type Result struct { type Result struct {
@@ -3,6 +3,7 @@ package edns
import ( import (
"context" "context"
"fmt" "fmt"
"net/url"
) )
func Query(ctx context.Context, options QueryOptions) Result { func Query(ctx context.Context, options QueryOptions) Result {
@@ -29,6 +30,18 @@ func Query(ctx context.Context, options QueryOptions) Result {
result.Error = &ErrorInfo{Class: "input", Message: err.Error()} result.Error = &ErrorInfo{Class: "input", Message: err.Error()}
return result return result
} }
if options.EndpointURL != "" {
if options.Protocol != "doh" {
result.Error = &ErrorInfo{Class: "input", Message: "custom --url applies only to DoH"}
return result
}
parsed, err := url.Parse(options.EndpointURL)
if err != nil || parsed.Scheme != "https" || parsed.Hostname() == "" {
result.Error = &ErrorInfo{Class: "input", Message: fmt.Sprintf("invalid DoH endpoint URL %q", options.EndpointURL)}
return result
}
provider = Provider{ID: "custom", Profile: "custom", DoHURL: options.EndpointURL}
}
result.Resolver = ResolverInfo{Provider: provider.ID, Profile: provider.Profile} result.Resolver = ResolverInfo{Provider: provider.ID, Profile: provider.Profile}
var response []byte var response []byte