Giter Site home page Giter Site logo

dnsr's Introduction

dnsr's People

Contributors

bookmoons avatar case avatar case-fastly avatar cee-dub avatar connyay avatar dependabot-preview[bot] avatar dependabot[bot] avatar domainrbot avatar integralist avatar maticmeznar avatar philpennock avatar rdoorn avatar wbond avatar ydnar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dnsr's Issues

Multitype query?

I'm hitting an issue due to the IP version split. Trying to query for both versions can lead to a network exchange on every resolution.

What would you guys think about supporting multitype queries? Behavior would be: First check cache for all the types. Only hit the network if we have none of them. Short circuit at the soonest point so you do the minimum network exchange. This is currently not possible externally, since cache is inaccessible.

Motivation is the common situation where a server only has an IPv4 address. You'd like to query for v6 but if you get v4 stick with it. So you don't keep hitting the network on every resolution.

rrs := resolver.ResolveAlternate("example.com", []string{"AAAA", "A"})

bookmoons/resolve-alternate has a working implementation.

Analagous logic with the current version that hits network every time:

example.com.  IN  A     192.0.2.1
func resolveIP() {
    ipv6s := resolver.Resolve("example.com", "AAAA")
    if len(ipv6s) > 0 {
        return ipv6s
    }
    ipv4s := resolver.Resolve("example.com", "A")
    if len(ipv4s) > 0 {
        // Cache for type A only hit after network query for AAAA
        return ipv4s
    }
    return emptyRRs
}

Set request deadline at 5s

We currently set 5s timeouts for each stage of a DNS request (connect, write, read) at 5s, which results in an unpredictable upper bound on latency. We would like to set an absolute upper boundfor latency at 5s, which should be straightforward to achieve with a network deadline on the client.

Do not only rely NS Record on parent domain

dnsr/resolver.go

Lines 124 to 127 in 5293a1c

nrrs, err := r.resolve(ctx, pname, "NS", depth)
if err == NXDOMAIN || err == ErrTimeout || err == context.DeadlineExceeded {
return nil, err
}

Such as xxxxx.sn.mynetname.net which is used for RouterBoard DDNS function (xxxxx is a random serial number on RouterBoard), the resolver trying to resolve a NS Record sn.mynetname.net, but the domain was stored on mynetname.net, and it received a NXDOMAIN response then return nil, it should try until the server mynetname.net also response an error

explore parallelism and racing

Per our discussion yesterday:

  • recently we've noticed some DNS timeouts in production, which we suspect could be something like DNSR querying a nameserver that's been taken out of rotation
  • the idea here is to explore checking all the available nameservers in parallel, then bail once there's an answer from any of them
  • goal is to address the "context deadline exceeded" errors we're seeing in production

panic in goroutine, `rmsg` is nil

I'm getting a nil panic from this line:

if rmsg.Rcode == dns.RcodeNameError {

Because this occurs in a goroutine spawned by this library, it's not recoverable

Full trace

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x1066173]

goroutine 22668 [running]:
github.com/domainr/dnsr.(*Resolver).exchangeIP(0xc0011de090, {0x481cb28, 0xc003b10c30}, {0xc0055ffa28, 0x13}, {0xc01925a140, 0xe}, {0xc0055ff668, 0x12}, {0x1f3bc0a, ...}, ...)
   /root/.cache/go-build/github.com/domainr/[email protected]/resolver.go:374 +0x6b3
github.com/domainr/dnsr.(*Resolver).exchange(0xc0011de090, {0x481cb28, 0xc003b10c30}, {0xc0055ffa28, 0x13}, {0xc0055ff668, 0x12}, {0x1f3bc0a, 0x3}, 0x1)
   /root/.cache/go-build/github.com/domainr/[email protected]/resolver.go:294 +0x185
github.com/domainr/dnsr.(*Resolver).iterateParents.func1({0xc0055ffa28?, 0xc001f8aa20?})
   /root/.cache/go-build/github.com/domainr/[email protected]/resolver.go:235 +0x89
created by github.com/domainr/dnsr.(*Resolver).iterateParents in goroutine 19692
   /root/.cache/go-build/github.com/domainr/[email protected]/resolver.go:234 +0x9ae

I've not managed to reliably reproduce it but I'm reasonably sure the bug comes from these lines

dnsr/resolver.go

Lines 354 to 359 in aa0c407

conn, err := dialer.DialContext(ctx, "tcp", addr)
if err == nil {
dconn := &dns.Conn{Conn: conn}
rmsg, dur, err = client.ExchangeWithConnContext(ctx, &qmsg, dconn)
conn.Close()
}

The err return from client.ExchangeWithConnContext is never checked because it's been shadowed by line 354

This means that resolvers with dnsr.WithTCPRetry() can panic if:

  1. UDP lookup is truncated
  2. TCP connection succeeds but lookup fails

In this case, the error check is ineffective at guarding against nil rmsg values because the error from the TCP lookup has been lost to the shadowed err var

dnsr/resolver.go

Lines 369 to 371 in aa0c407

if err != nil {
return nil, err
}

Partial or empty TXT answers

First off great lib, okay so when I do resolver.ResolveCtx(ctx, "google.com.", "TXT") I get 6 TXT records:

Resolver settings:

var resolver *dnsr.Resolver = dnsr.NewResolver(dnsr.WithTimeout(5*time.Second), dnsr.WithCache(10000), dnsr.WithExpiry())
==================== Test output for //ogcode/services/certificate-bot/lib/resolver:resolver_test:
╭─── resolve("google.com.", "TXT", 1)
│   ╭─── resolve("google.com.", "NS", 2)
│   │   ╭─── resolve("com.", "NS", 3)
    X    29ms (T- 4999ms): dig +norecurse @b.root-servers.net. com. NS  # rmsg: NOERROR Answer: 0 NS: 13 Extra: 12 == CANCELED ==
X    26ms (T- 4990ms): dig +norecurse @a.gtld-servers.net. one.com. NS  # rmsg: NOERROR Answer: 0 NS: 2 Extra: 0 == CANCELED ==
│   │   │    9ms (T- 4999ms): dig +norecurse @e.root-servers.net. com. NS  # rmsg: NOERROR Answer: 0 NS: 13 Extra: 15
│   │   ╰─── 9ms: resolve("com.", "NS", 3) # [26]RR = NS(com.)=a.gtld-servers.net. NS(com.)=b.gtld-servers.net. ...
│   │    7ms (T- 4990ms): dig +norecurse @b.gtld-servers.net. google.com. NS  # rmsg: NOERROR Answer: 0 NS: 4 Extra: 8
│   ╰─── 17ms: resolve("google.com.", "NS", 2) # [8]RR = NS(google.com.)=ns2.google.com. NS(google.com.)=ns1.google.com. ...
        X    29ms (T- 4999ms): dig +norecurse @b.root-servers.net. com. NS  # rmsg: NOERROR Answer: 0 NS: 13 Extra: 12 == CANCELED ==
    X    26ms (T- 4990ms): dig +norecurse @a.gtld-servers.net. google.com. NS  # rmsg: NOERROR Answer: 0 NS: 4 Extra: 8 == CANCELED ==
│    36ms (T- 4982ms): dig +norecurse @ns1.google.com. google.com. TXT  # rmsg: NOERROR Answer: 6 NS: 0 Extra: 0
╰─── 54ms: resolve("google.com.", "TXT", 1) # [10]RR = TXT(google.com.)=google-site-verification=wD8N7i1JTNTkezJ49swvWW48f8_9xveREV4oB-0Hf5o TXT(google.com.)=MS=E4A68B9AB2BB9670BCE15412F62916164C0B20BB ...
TXT google-site-verification=wD8N7i1JTNTkezJ49swvWW48f8_9xveREV4oB-0Hf5o
TXT MS=E4A68B9AB2BB9670BCE15412F62916164C0B20BB
TXT facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95
TXT globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8=
TXT docusign=1b0a6754-49b1-4db5-8540-d2c12664b289
TXT apple-domain-verification=30afIBcvSuDV2PLX
NS ns2.google.com.
NS ns1.google.com.
NS ns3.google.com.
NS ns4.google.com.

but if i try dig i get a lot more TXT records

> dig +norecurse +short @ns2.google.com. google.com. TXT
"docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e"
"docusign=1b0a6754-49b1-4db5-8540-d2c12664b289"
"globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8="
"MS=E4A68B9AB2BB9670BCE15412F62916164C0B20BB"
"webexdomainverification.8YX6G=6e6922db-e3e6-4a36-904e-a805c28087fa"
"facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95"
"google-site-verification=wD8N7i1JTNTkezJ49swvWW48f8_9xveREV4oB-0Hf5o"
"atlassian-domain-verification=5YjTmWmjI92ewqkx2oXmBaD60Td9zWon9r6eakvHX6B77zzkFQto8PQ9QsKnbf4I"
"v=spf1 include:_spf.google.com ~all"
"apple-domain-verification=30afIBcvSuDV2PLX"
"google-site-verification=TV9-DBe4R80X4v0M4U_bd_J9cpOJM0nikft0jAgjmsQ"
"onetrust-domain-verification=de01ed21f2fa4d8781cbc3ffb89cf4ef"

I also tried with cloudflare.com. it should have a bunch of TXT records but dnsr returns 0 TXT records.

invalid cache locking when expiry is enabled

When cache expiration is enabled, the get() method may delete cache entries .
This could lead to a panic , since the get() method uses an RLock , allowing other goroutines to iterate the map while the deletion takes place.

Add TTL support?

I'm evaluating this for possible use in another project. It seems to be the nicest resolver available, but I need something with an expiring cache that respects TTL.

Would the team consider a PR to support TTL?

CNAME only in response

If a server is doing a recursion, asks for a record type that is not CNAME, but gets a CNAME response, then it should restart the query with the name from the CNAME record, merge the response from the restarted query with the CNAME response and return the combined response to whoever it was doing the recursion for.

example:

➜  ~ dig @127.0.0.1 -p 5000 +tcp translate.google.com A

; <<>> DiG 9.18.25 <<>> @127.0.0.1 -p 5000 +tcp translate.google.com A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41052
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;translate.google.com.		IN	A

;; ANSWER SECTION:
translate.google.com.	300	IN	CNAME	www3.l.google.com.

I want in the response also the IP for A type:

www3.l.google.com.	300	IN	A	172.217.18.206

Failing test: func TestHerokuA()

This test started failing a few days ago:

func TestHerokuA(t *testing.T) {
	r := New(0)
	rrs, err := r.ResolveErr("us-east-1-a.route.herokuapp.com", "A")
	st.Expect(t, err, nil)
	st.Expect(t, count(rrs, func(rr RR) bool { return rr.Type == "A" }) >= 1, true)
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.