diff --git a/cmd/cli/cli.go b/cmd/cli/cli.go index 861472a..aabd3cc 100644 --- a/cmd/cli/cli.go +++ b/cmd/cli/cli.go @@ -1473,7 +1473,11 @@ func processNoConfigFlags(noConfigStart bool) { endpointAndTyp := func(endpoint string) (string, string) { typ := ctrld.ResolverTypeFromEndpoint(endpoint) - return strings.TrimPrefix(endpoint, "quic://"), typ + endpoint = strings.TrimPrefix(endpoint, "quic://") + if after, found := strings.CutPrefix(endpoint, "h3://"); found { + endpoint = "https://" + after + } + return endpoint, typ } pEndpoint, pType := endpointAndTyp(primaryUpstream) upstream := map[string]*ctrld.UpstreamConfig{ diff --git a/config.go b/config.go index e09fdad..ab22045 100644 --- a/config.go +++ b/config.go @@ -59,6 +59,10 @@ const ( controlDComDomain = "controld.com" controlDNetDomain = "controld.net" controlDDevDomain = "controld.dev" + + endpointPrefixHTTPS = "https://" + endpointPrefixQUIC = "quic://" + endpointPrefixH3 = "h3://" ) var ( @@ -677,12 +681,16 @@ func (uc *UpstreamConfig) netForDNSType(dnsType uint16) (string, string) { // initDoHScheme initializes the endpoint scheme for DoH/DoH3 upstream if not present. func (uc *UpstreamConfig) initDoHScheme() { switch uc.Type { - case ResolverTypeDOH, ResolverTypeDOH3: + case ResolverTypeDOH: + case ResolverTypeDOH3: + if after, found := strings.CutPrefix(uc.Endpoint, endpointPrefixH3); found { + uc.Endpoint = endpointPrefixHTTPS + after + } default: return } - if !strings.HasPrefix(uc.Endpoint, "https://") { - uc.Endpoint = "https://" + uc.Endpoint + if !strings.HasPrefix(uc.Endpoint, endpointPrefixHTTPS) { + uc.Endpoint = endpointPrefixHTTPS + uc.Endpoint } } @@ -767,13 +775,16 @@ func defaultPortFor(typ string) string { // - If endpoint is an IP address -> ResolverTypeLegacy // - If endpoint starts with "https://" -> ResolverTypeDOH // - If endpoint starts with "quic://" -> ResolverTypeDOQ +// - If endpoint starts with "h3://" -> ResolverTypeDOH3 // - For anything else -> ResolverTypeDOT func ResolverTypeFromEndpoint(endpoint string) string { switch { - case strings.HasPrefix(endpoint, "https://"): + case strings.HasPrefix(endpoint, endpointPrefixHTTPS): return ResolverTypeDOH - case strings.HasPrefix(endpoint, "quic://"): + case strings.HasPrefix(endpoint, endpointPrefixQUIC): return ResolverTypeDOQ + case strings.HasPrefix(endpoint, endpointPrefixH3): + return ResolverTypeDOH3 } host := endpoint if strings.Contains(endpoint, ":") { diff --git a/config_internal_test.go b/config_internal_test.go index 96beddc..2dc05c3 100644 --- a/config_internal_test.go +++ b/config_internal_test.go @@ -178,6 +178,27 @@ func TestUpstreamConfig_Init(t *testing.T) { u: u2, }, }, + { + "h3", + &UpstreamConfig{ + Name: "doh3", + Type: "doh3", + Endpoint: "h3://example.com", + BootstrapIP: "", + Domain: "", + Timeout: 0, + }, + &UpstreamConfig{ + Name: "doh3", + Type: "doh3", + Endpoint: "https://example.com", + BootstrapIP: "", + Domain: "example.com", + Timeout: 0, + IPStack: IpStackBoth, + u: u1, + }, + }, } for _, tc := range tests {