wahern / cqueues

Continuation Queues: Embeddable asynchronous networking, threading, and notification framework for Lua on Unix.
http://25thandclement.com/~william/projects/cqueues.html
MIT License
244 stars 37 forks source link

Add simple dns lookup function to cqueues.dns #164

Open daurnimator opened 7 years ago

daurnimator commented 7 years ago

It can be complex figuring out how to do a 'normal' dns query.

e.g. to lookup an ip for google.com, you currently need something like:

local dns = require "cqueues.dns"
local host = "google.com"
local res, err, errno = dns.query(host)
if not res then return nil, err, errno end
local ip
for rec in res:grep{section = "answer", type = "A", class = "IN", name = host .. "."} do
    ip = rec:addr()
    break
end
if ip then
    return ip
else
    return nil, "not found"
end

Add a simpler interface.

daurnimator commented 7 years ago

My above code is wrong: checking for name like I did doesn't work if e.g. there is a CNAME pointing to somewhere else (and that's also included) e.g. checkip.dyndns.org:

;; [HEADER]
;;    qid : 0
;;     qr : QUERY(0)
;; opcode : QUERY(0)
;;     aa : NON-AUTHORITATIVE(0)
;;     tc : NOT-TRUNCATED(0)
;;     rd : RECURSION-NOT-DESIRED(0)
;;     ra : RECURSION-NOT-ALLOWED(0)
;;  rcode : NOERROR(0)

;; [QUESTION:1]
;checkip.dyndns.org. IN A

;; [ANSWER:4]
checkip.dyndns.org. 197 IN CNAME checkip.dyndns.com.
checkip.dyndns.com. 481 IN A 216.146.38.70
checkip.dyndns.com. 481 IN A 216.146.43.70
checkip.dyndns.com. 481 IN A 91.198.22.70

What should the process be for getting the IP out of a response?

Another guess:

    local host = name .. "."
    for _=1,8 do -- avoid loops
        for rec in res:grep{section = "answer", class = "IN", name = host} do
            local t = rec:type()
            if t == dns_record.A or t == dns_record.AAAA then
                return rec:addr()
            elseif t == dns_record.CNAME then
                host = rec:host()
                break
            end
        end
        if host == nil then
            break
        end
    end
    return nil, "not found"
daurnimator commented 6 years ago

Working with @Habbie I wrote this:

-- `type` parameter is what sort of records you want to find could be "A" or
-- "AAAA" or `nil` if you want to filter yourself e.g. to implement
-- https://www.ietf.org/archive/id/draft-vavrusa-dnsop-aaaa-for-free-00.txt
local function each_matching_record(pkt, name, type)
    -- First need to do CNAME chasing
    local params = {
        section = "answer";
        class = cqueues_dns_record.IN;
        type = cqueues_dns_record.CNAME;
        name = name .. ".";
    }
    for _=1, 8 do -- avoid cname loops
        -- Ignores any CNAME record past the first (which should never occur anyway)
        local func, state, first = pkt:grep(params)
        local record = func(state, first)
        if record == nil then
            -- Not found
            break
        end
        params.name = record:host()
    end
    params.type = type
    return pkt:grep(params)
end

See https://github.com/daurnimator/lua-http/pull/120