diff --git a/resolver/config.go b/resolver/config.go index 13e28c62..01bddde0 100644 --- a/resolver/config.go +++ b/resolver/config.go @@ -126,14 +126,6 @@ The format is: "protocol://ip:port?parameter=value¶meter=value" "dot://dns.quad9.net?ip=149.112.112.112&verify=&name=Quad9&blockedif=empty", }, }, - { - Name: "Quad9 DoH", - Action: config.QuickReplace, - Value: []string{ - "https://dns.quad9.net/dns-query?ip=9.9.9.9&name=Quad9", - "https://dns.quad9.net/dns-query?ip=149.112.112.112&name=Quad9", - }, - }, { Name: "AdGuard", Action: config.QuickReplace, @@ -142,14 +134,6 @@ The format is: "protocol://ip:port?parameter=value¶meter=value" "dot://dns.adguard.com?ip=94.140.15.15&name=AdGuard&blockedif=zeroip", }, }, - { - Name: "AdGuard DoH", - Action: config.QuickReplace, - Value: []string{ - "https://dns.adguard.com/dns-query?ip=94.140.14.14&name=AdGuard", - "https://dns.adguard.com/dns-query?ip=94.140.15.15&name=AdGuard", - }, - }, { Name: "Foundation for Applied Privacy", Action: config.QuickReplace, @@ -157,13 +141,6 @@ The format is: "protocol://ip:port?parameter=value¶meter=value" "dot://dot1.applied-privacy.net?ip=94.130.106.88&name=AppliedPrivacy", }, }, - { - Name: "Foundation for Applied Privacy DoH", - Action: config.QuickReplace, - Value: []string{ - "https://dot1.applied-privacy.net/query?ip=94.130.106.88&name=AppliedPrivacy", - }, - }, { Name: "Cloudflare (with Malware Filter)", Action: config.QuickReplace, @@ -172,14 +149,6 @@ The format is: "protocol://ip:port?parameter=value¶meter=value" "dot://cloudflare-dns.com?ip=1.0.0.2&name=Cloudflare&blockedif=zeroip", }, }, - { - Name: "Cloudflare (with Malware Filter) DoH", - Action: config.QuickReplace, - Value: []string{ - "https://cloudflare-dns.com/dns-query?ip=1.1.1.2&name=Cloudflare", - "https://cloudflare-dns.com/dns-query?ip=1.0.0.2&name=Cloudflare", - }, - }, }, "self:detail:internalSpecialUseDomains": internalSpecialUseDomains, "self:detail:connectivityDomains": netenv.ConnectivityDomains, diff --git a/resolver/resolver-https.go b/resolver/resolver-https.go index bb0f0d28..7fd6c14b 100644 --- a/resolver/resolver-https.go +++ b/resolver/resolver-https.go @@ -39,12 +39,16 @@ func (tq *HttpsQuery) MakeCacheRecord(reply *dns.Msg, resolverInfo *ResolverInfo // NewHTTPSResolver returns a new HttpsResolver. func NewHTTPSResolver(resolver *Resolver) *HttpsResolver { - tr := &http.Transport{ - TLSClientConfig: &tls.Config{ - MinVersion: tls.VersionTLS12, - ServerName: resolver.VerifyDomain, - // TODO: use portbase rng - }, + tr := &http.Transport{} + + if resolver.ServerAddress != "" { + tr = &http.Transport{ + TLSClientConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + ServerName: resolver.VerifyDomain, + // TODO: use portbase rng + }, + } } client := &http.Client{Transport: tr} @@ -61,20 +65,26 @@ func NewHTTPSResolver(resolver *Resolver) *HttpsResolver { // Query executes the given query against the resolver. func (hr *HttpsResolver) Query(ctx context.Context, q *Query) (*RRCache, error) { - // Get resolver connection. dnsQuery := new(dns.Msg) dnsQuery.SetQuestion(q.FQDN, uint16(q.QType)) + // Pack query and convert to base64 string buf, err := dnsQuery.Pack() - if err != nil { return nil, err } b64dns := base64.RawStdEncoding.EncodeToString(buf) + host := hr.resolver.VerifyDomain + + if hr.resolver.ServerAddress != "" { + host = hr.resolver.ServerAddress + } + + // Build and execute http reuqest url := &url.URL{ Scheme: "https", - Host: hr.resolver.ServerAddress, + Host: host, Path: hr.resolver.Path, ForceQuery: true, RawQuery: fmt.Sprintf("dns=%s", b64dns), @@ -87,20 +97,20 @@ func (hr *HttpsResolver) Query(ctx context.Context, q *Query) (*RRCache, error) } resp, err := hr.Client.Do(request) - if err != nil { return nil, err } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + // Try to read the result + body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } - reply := new(dns.Msg) - err = reply.Unpack(body) + reply := new(dns.Msg) + + err = reply.Unpack(body) if err != nil { return nil, err } diff --git a/resolver/resolvers.go b/resolver/resolvers.go index 361828de..35101586 100644 --- a/resolver/resolvers.go +++ b/resolver/resolvers.go @@ -105,12 +105,15 @@ func createResolver(resolverURL, source string) (*Resolver, bool, error) { return nil, false, fmt.Errorf("DNS resolver scheme %q invalid", u.Scheme) } + // Check if we are using domain name and if it's in a valid scheme ip := net.ParseIP(u.Hostname()) - isHostnameDomain := (ip == nil) - if ip == nil && u.Scheme != ServerTypeDoH { + hostnameIsDomaion := (ip == nil) + if ip == nil && u.Scheme != ServerTypeDoH && u.Scheme != ServerTypeDoT { return nil, false, fmt.Errorf("resolver IP %q invalid", u.Hostname()) } + path := u.Path // Used for DoH + // Add default port for scheme if it is missing. port, err := parsePortFromURL(u) if err != nil { @@ -119,41 +122,31 @@ func createResolver(resolverURL, source string) (*Resolver, bool, error) { // Get parameters and check if keys exist. query := u.Query() - err = checkURLParameterValidity(u.Scheme, isHostnameDomain, query) + err = checkURLParameterValidity(u.Scheme, hostnameIsDomaion, query) if err != nil { return nil, false, err } - // Check domain verification config. + // Get IP address and domain name from paramters. serverAddress := "" - paramterServerIP := query.Get(parameterIP) + serverIPParamter := query.Get(parameterIP) verifyDomain := query.Get(parameterVerify) if u.Scheme == ServerTypeDoT || u.Scheme == ServerTypeDoH { switch { - case isHostnameDomain && paramterServerIP != "": // domain and ip as parameter - ip = net.ParseIP(paramterServerIP) - serverAddress = net.JoinHostPort(paramterServerIP, strconv.Itoa(int(port))) + case hostnameIsDomaion && serverIPParamter != "": // domain and ip as parameter + ip = net.ParseIP(serverIPParamter) + serverAddress = net.JoinHostPort(serverIPParamter, strconv.Itoa(int(port))) verifyDomain = u.Hostname() - case !isHostnameDomain && verifyDomain != "": // ip and domain as parameter + case !hostnameIsDomaion && verifyDomain != "": // ip and domain as parameter serverAddress = net.JoinHostPort(ip.String(), strconv.Itoa(int(port))) - case isHostnameDomain && verifyDomain == "" && paramterServerIP == "": // only domain + case hostnameIsDomaion && verifyDomain == "" && serverIPParamter == "": // only domain verifyDomain = u.Hostname() } } else { serverAddress = net.JoinHostPort(ip.String(), strconv.Itoa(int(port))) } - // Check path for https (doh) request - path := query.Get(parameterPath) - if u.Path != "" { - path = u.Path - } - - if path != "" && !strings.HasPrefix(path, "/") { - path = "/" + path - } - // Check block detection type. blockType := query.Get(parameterBlockedIf) if blockType == "" { @@ -212,17 +205,11 @@ func createResolver(resolverURL, source string) (*Resolver, bool, error) { } } - // Resolve ip if was not specfied by the user - err = checkAndResolveServerAddressAndPort(newResolver) - if err != nil { - return nil, false, err - } - newResolver.Conn = resolverConnFactory(newResolver) return newResolver, false, nil } -func checkURLParameterValidity(scheme string, isHostnameDomain bool, query url.Values) error { +func checkURLParameterValidity(scheme string, hostnameIsDomaion bool, query url.Values) error { for key := range query { switch key { case parameterName, @@ -245,47 +232,17 @@ func checkURLParameterValidity(scheme string, isHostnameDomain bool, query url.V if scheme == ServerTypeDoT || scheme == ServerTypeDoH { switch { - case isHostnameDomain && verifyDomain != "": - return fmt.Errorf("cannot have verify parameter with a domain as a hostname") - case !isHostnameDomain && verifyDomain == "": - return fmt.Errorf("verify paremeter must be set when using ip as domain") - case !isHostnameDomain && paramterServerIP != "": - return fmt.Errorf("cannot have ip parameter while domain is an ip") + case hostnameIsDomaion && verifyDomain != "": + return fmt.Errorf("cannot set the domain name via both the hostname in the URL and the verify parameter") + case !hostnameIsDomaion && verifyDomain == "": + return fmt.Errorf("verify parameter must be set when using ip as domain") + case !hostnameIsDomaion && paramterServerIP != "": + return fmt.Errorf("cannot set the IP address via both the hostname in the URL and the ip parameter") } } else { if verifyDomain != "" { - return fmt.Errorf("domain verification only supported in DoT and DoH") + return fmt.Errorf("domain verification is only supported by DoT and DoH servers") } - if verifyDomain == "" && !isHostnameDomain { - return fmt.Errorf("DoT must have a verify query parameter set") - } - } - - if scheme != ServerTypeDoH { - path := query.Get(parameterPath) - if path != "" { - return fmt.Errorf("path parameter is only supported in DoH") - } - } - - return nil -} - -func checkAndResolveServerAddressAndPort(resolver *Resolver) error { - if resolver.ServerAddress == "" { - resolverIps, err := resolveDomainIP(context.Background(), resolver.VerifyDomain) - if err != nil { - return err - } - - if len(resolverIps) == 0 { - return fmt.Errorf("no valid IPs resolved for %s", resolver.VerifyDomain) - } - ip := resolverIps[0] - port := int(resolver.Info.Port) - resolver.ServerAddress = net.JoinHostPort(ip.String(), strconv.Itoa(port)) - resolver.Info.IP = ip - resolver.Info.IPScope = netutils.GetIPScope(ip) } return nil @@ -348,7 +305,7 @@ func parsePortFromURL(url *url.URL) (uint16, error) { // There is a port in the url parsedPort, err := strconv.ParseUint(hostPort, 10, 16) if err != nil { - return 0, fmt.Errorf("resolver port %q invalid", url.Port()) + return 0, fmt.Errorf("invalid port %q", url.Port()) } port = uint16(parsedPort) } else {