Refatoring and removed pre resolving of dot, doh
This commit is contained in:
@@ -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",
|
"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",
|
Name: "AdGuard",
|
||||||
Action: config.QuickReplace,
|
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",
|
"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",
|
Name: "Foundation for Applied Privacy",
|
||||||
Action: config.QuickReplace,
|
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",
|
"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)",
|
Name: "Cloudflare (with Malware Filter)",
|
||||||
Action: config.QuickReplace,
|
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",
|
"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:internalSpecialUseDomains": internalSpecialUseDomains,
|
||||||
"self:detail:connectivityDomains": netenv.ConnectivityDomains,
|
"self:detail:connectivityDomains": netenv.ConnectivityDomains,
|
||||||
|
|||||||
@@ -39,12 +39,16 @@ func (tq *HttpsQuery) MakeCacheRecord(reply *dns.Msg, resolverInfo *ResolverInfo
|
|||||||
|
|
||||||
// NewHTTPSResolver returns a new HttpsResolver.
|
// NewHTTPSResolver returns a new HttpsResolver.
|
||||||
func NewHTTPSResolver(resolver *Resolver) *HttpsResolver {
|
func NewHTTPSResolver(resolver *Resolver) *HttpsResolver {
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{}
|
||||||
TLSClientConfig: &tls.Config{
|
|
||||||
MinVersion: tls.VersionTLS12,
|
if resolver.ServerAddress != "" {
|
||||||
ServerName: resolver.VerifyDomain,
|
tr = &http.Transport{
|
||||||
// TODO: use portbase rng
|
TLSClientConfig: &tls.Config{
|
||||||
},
|
MinVersion: tls.VersionTLS12,
|
||||||
|
ServerName: resolver.VerifyDomain,
|
||||||
|
// TODO: use portbase rng
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{Transport: tr}
|
client := &http.Client{Transport: tr}
|
||||||
@@ -61,20 +65,26 @@ func NewHTTPSResolver(resolver *Resolver) *HttpsResolver {
|
|||||||
|
|
||||||
// Query executes the given query against the resolver.
|
// Query executes the given query against the resolver.
|
||||||
func (hr *HttpsResolver) Query(ctx context.Context, q *Query) (*RRCache, error) {
|
func (hr *HttpsResolver) Query(ctx context.Context, q *Query) (*RRCache, error) {
|
||||||
// Get resolver connection.
|
|
||||||
dnsQuery := new(dns.Msg)
|
dnsQuery := new(dns.Msg)
|
||||||
dnsQuery.SetQuestion(q.FQDN, uint16(q.QType))
|
dnsQuery.SetQuestion(q.FQDN, uint16(q.QType))
|
||||||
|
|
||||||
|
// Pack query and convert to base64 string
|
||||||
buf, err := dnsQuery.Pack()
|
buf, err := dnsQuery.Pack()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b64dns := base64.RawStdEncoding.EncodeToString(buf)
|
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{
|
url := &url.URL{
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Host: hr.resolver.ServerAddress,
|
Host: host,
|
||||||
Path: hr.resolver.Path,
|
Path: hr.resolver.Path,
|
||||||
ForceQuery: true,
|
ForceQuery: true,
|
||||||
RawQuery: fmt.Sprintf("dns=%s", b64dns),
|
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)
|
resp, err := hr.Client.Do(request)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
|
|
||||||
|
// Try to read the result
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reply := new(dns.Msg)
|
|
||||||
err = reply.Unpack(body)
|
|
||||||
|
|
||||||
|
reply := new(dns.Msg)
|
||||||
|
|
||||||
|
err = reply.Unpack(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,12 +105,15 @@ func createResolver(resolverURL, source string) (*Resolver, bool, error) {
|
|||||||
return nil, false, fmt.Errorf("DNS resolver scheme %q invalid", u.Scheme)
|
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())
|
ip := net.ParseIP(u.Hostname())
|
||||||
isHostnameDomain := (ip == nil)
|
hostnameIsDomaion := (ip == nil)
|
||||||
if ip == nil && u.Scheme != ServerTypeDoH {
|
if ip == nil && u.Scheme != ServerTypeDoH && u.Scheme != ServerTypeDoT {
|
||||||
return nil, false, fmt.Errorf("resolver IP %q invalid", u.Hostname())
|
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.
|
// Add default port for scheme if it is missing.
|
||||||
port, err := parsePortFromURL(u)
|
port, err := parsePortFromURL(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -119,41 +122,31 @@ func createResolver(resolverURL, source string) (*Resolver, bool, error) {
|
|||||||
|
|
||||||
// Get parameters and check if keys exist.
|
// Get parameters and check if keys exist.
|
||||||
query := u.Query()
|
query := u.Query()
|
||||||
err = checkURLParameterValidity(u.Scheme, isHostnameDomain, query)
|
err = checkURLParameterValidity(u.Scheme, hostnameIsDomaion, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check domain verification config.
|
// Get IP address and domain name from paramters.
|
||||||
serverAddress := ""
|
serverAddress := ""
|
||||||
paramterServerIP := query.Get(parameterIP)
|
serverIPParamter := query.Get(parameterIP)
|
||||||
verifyDomain := query.Get(parameterVerify)
|
verifyDomain := query.Get(parameterVerify)
|
||||||
|
|
||||||
if u.Scheme == ServerTypeDoT || u.Scheme == ServerTypeDoH {
|
if u.Scheme == ServerTypeDoT || u.Scheme == ServerTypeDoH {
|
||||||
switch {
|
switch {
|
||||||
case isHostnameDomain && paramterServerIP != "": // domain and ip as parameter
|
case hostnameIsDomaion && serverIPParamter != "": // domain and ip as parameter
|
||||||
ip = net.ParseIP(paramterServerIP)
|
ip = net.ParseIP(serverIPParamter)
|
||||||
serverAddress = net.JoinHostPort(paramterServerIP, strconv.Itoa(int(port)))
|
serverAddress = net.JoinHostPort(serverIPParamter, strconv.Itoa(int(port)))
|
||||||
verifyDomain = u.Hostname()
|
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)))
|
serverAddress = net.JoinHostPort(ip.String(), strconv.Itoa(int(port)))
|
||||||
case isHostnameDomain && verifyDomain == "" && paramterServerIP == "": // only domain
|
case hostnameIsDomaion && verifyDomain == "" && serverIPParamter == "": // only domain
|
||||||
verifyDomain = u.Hostname()
|
verifyDomain = u.Hostname()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
serverAddress = net.JoinHostPort(ip.String(), strconv.Itoa(int(port)))
|
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.
|
// Check block detection type.
|
||||||
blockType := query.Get(parameterBlockedIf)
|
blockType := query.Get(parameterBlockedIf)
|
||||||
if blockType == "" {
|
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)
|
newResolver.Conn = resolverConnFactory(newResolver)
|
||||||
return newResolver, false, nil
|
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 {
|
for key := range query {
|
||||||
switch key {
|
switch key {
|
||||||
case parameterName,
|
case parameterName,
|
||||||
@@ -245,47 +232,17 @@ func checkURLParameterValidity(scheme string, isHostnameDomain bool, query url.V
|
|||||||
if scheme == ServerTypeDoT || scheme == ServerTypeDoH {
|
if scheme == ServerTypeDoT || scheme == ServerTypeDoH {
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case isHostnameDomain && verifyDomain != "":
|
case hostnameIsDomaion && verifyDomain != "":
|
||||||
return fmt.Errorf("cannot have verify parameter with a domain as a hostname")
|
return fmt.Errorf("cannot set the domain name via both the hostname in the URL and the verify parameter")
|
||||||
case !isHostnameDomain && verifyDomain == "":
|
case !hostnameIsDomaion && verifyDomain == "":
|
||||||
return fmt.Errorf("verify paremeter must be set when using ip as domain")
|
return fmt.Errorf("verify parameter must be set when using ip as domain")
|
||||||
case !isHostnameDomain && paramterServerIP != "":
|
case !hostnameIsDomaion && paramterServerIP != "":
|
||||||
return fmt.Errorf("cannot have ip parameter while domain is an ip")
|
return fmt.Errorf("cannot set the IP address via both the hostname in the URL and the ip parameter")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if verifyDomain != "" {
|
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
|
return nil
|
||||||
@@ -348,7 +305,7 @@ func parsePortFromURL(url *url.URL) (uint16, error) {
|
|||||||
// There is a port in the url
|
// There is a port in the url
|
||||||
parsedPort, err := strconv.ParseUint(hostPort, 10, 16)
|
parsedPort, err := strconv.ParseUint(hostPort, 10, 16)
|
||||||
if err != nil {
|
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)
|
port = uint16(parsedPort)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user