Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cached HOST_NOT_FOUND should not take precendence #134

Open
jobhh opened this issue Oct 2, 2020 · 1 comment
Open

Cached HOST_NOT_FOUND should not take precendence #134

jobhh opened this issue Oct 2, 2020 · 1 comment

Comments

@jobhh
Copy link

@jobhh jobhh commented Oct 2, 2020

I first thought I encountered a race condition and a bug related to the caching mechanism. But it's likely due to the same issue.

Observations:

  1. When I start my app and run "raceconditionTest()" sometimes it returns 10.2.2.2 for "test", which is the correct local IP, but most of the times it returns null. Which means the result of 8.8.8.8 is used, and not from 10.1.1.1 (8.8.8.8 seems to be faster than my local DNS).
  2. When "test" failed to resolve, "test2" will always be null. This is often the case for raceconditionTest() and always the case for cacheTest().

My input:

  1. I don't think a cached HOST_NOT_FOUND result should take precedence. I created a new Resolver with another server to query, using the cached result from another server in this situation seems illogical.
  2. I haven't look closely at the code, but I assume an ExtendedResolver queries all servers and uses the first result it gets. In such a situation I don't think a HOST_NOT_FOUND result should be used when the other server(s) might return the correct value.

Kotlin code (running on Android 8. 10.1.1.1 is my local OPNsense instance, running Unbound DNS):

    private fun raceconditionTest(): {
            val test = resolveDomain("someserver.mydomain.it", listOf("10.1.1.1", "8.8.8.8"))
            val test2 = resolveDomain("someserver.mydomain.it", listOf("10.1.1.1", ))
    }

    private fun cacheTest(): {
            val test = resolveDomain("someserver.mydomain.it", listOf("8.8.8.8"))
            val test2 = resolveDomain("someserver.mydomain.it", listOf("10.1.1.1", ))
    }

    private fun resolveDomain(domain: String, serverNames: List<String>): String? {
        try {
            val resolver: Resolver = if (serverNames.size > 1) {
                ExtendedResolver(serverNames.toTypedArray())
            } else {
                SimpleResolver(serverNames[0])
            }
            
            val lookup = Lookup(domain)
            lookup.setResolver(resolver)
            
            val recs: Array<Record> = lookup.run() ?: return null
            for (rec in recs) {
                return rec.rdataToString()
            }
        } catch (e: Exception) { }
        return null
    }
@ibauersachs
Copy link
Member

@ibauersachs ibauersachs commented Oct 2, 2020

I first thought I encountered a race condition and a bug related to the caching mechanism. But it's likely due to the same issue.

Observations:

  1. When I start my app and run "raceconditionTest()" sometimes it returns 10.2.2.2 for "test", which is the correct local IP, but most of the times it returns null. Which means the result of 8.8.8.8 is used, and not from 10.1.1.1 (8.8.8.8 seems to be faster than my local DNS).
  2. When "test" failed to resolve, "test2" will always be null. This is often the case for raceconditionTest() and always the case for cacheTest().

My input:

  1. I don't think a cached HOST_NOT_FOUND result should take precedence. I created a new Resolver with another server to query, using the cached result from another server in this situation seems illogical.

HOST_NOT_FOUND (or NXDOMAIN in actual DNS terms) is a valid DNS response. It's thus correctly taken as the first answer. The Resolver does not do the caching, this is done by Lookup. The default cache for a new Lookup instance is the static cache instance, which can be changed. You could argue that changing the resolver of a Lookup instance should reset the cache, but I'm not sure this would be correct either.

  1. I haven't look closely at the code, but I assume an ExtendedResolver queries all servers and uses the first result it gets. In such a situation I don't think a HOST_NOT_FOUND result should be used when the other server(s) might return the correct value.

Yes, the fastest response is used.

This is all about a split-brain DNS scenario. I understand your issue and I was annoyed myself by the same behavior of Windows. As a developer however, I don't know how to properly deal with this. Simply continuing to query servers just because a valid response isn't deemed valid in some setups isn't going to cut it.
As a network admin, I meanwhile consider split-brain DNS a broken setup. It's something that just doesn't work well and not at all anymore with DNSSEC.

I'm open to ideas that don't change the current default behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.