2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
9 local server
= require
"net.server";
10 local new_resolver
= require
"net.dns".resolver
;
12 local log = require
"util.logger".init("adns");
14 local coroutine
, pcall
= coroutine
, pcall
;
15 local setmetatable
= setmetatable
;
17 local function dummy_send(sock
, data
, i
, j
) return (j
-i
)+1; end -- luacheck: ignore 212
22 local async_resolver_methods
= {};
23 local async_resolver_mt
= { __index
= async_resolver_methods
};
25 local query_methods
= {};
26 local query_mt
= { __index
= query_methods
};
28 local function new_async_socket(sock
, resolver
)
29 local peername
= "<unknown>";
32 function listener
.onincoming(conn
, data
) -- luacheck: ignore 212/conn
34 resolver
:feed(handler
, data
);
37 function listener
.ondisconnect(conn
, err
)
39 log("warn", "DNS socket for %s disconnected: %s", peername
, err
);
40 local servers
= resolver
.server
;
41 if resolver
.socketset
[conn
] == resolver
.best_server
and resolver
.best_server
== #servers
then
42 log("error", "Exhausted all %d configured DNS servers, next lookup will try %s again", #servers
, servers
[1]);
45 resolver
:servfail(conn
); -- Let the magic commence
50 handler
, err
= server
.wrapclient(sock
, "dns", 53, listener
);
56 handler
.settimeout
= function () end
57 handler
.setsockname
= function (_
, ...) return sock
:setsockname(...); end
58 handler
.setpeername
= function (_
, ...) peername
= (...); local ret
, err
= sock
:setpeername(...); _
:set_send(dummy_send
); return ret
, err
; end
59 handler
.connect
= function (_
, ...) return sock
:connect(...) end
60 --handler.send = function (_, data) _:write(data); return _.sendbuffer and _.sendbuffer(); end
61 handler
.send
= function (_
, data
)
62 log("debug", "Sending DNS query to %s", peername
);
63 return sock
:send(data
);
68 function async_resolver_methods
:lookup(handler
, qname
, qtype
, qclass
)
69 local resolver
= self
._resolver
;
70 return coroutine
.wrap(function (peek
)
72 log("debug", "Records for %s already cached, using those...", qname
);
76 log("debug", "Records for %s not in cache, sending query (%s)...", qname
, coroutine
.running());
77 local ok
, err
= resolver
:query(qname
, qtype
, qclass
);
79 coroutine
.yield(setmetatable({ resolver
, qclass
or "IN", qtype
or "A", qname
, coroutine
.running()}, query_mt
)); -- Wait for reply
80 log("debug", "Reply for %s (%s)", qname
, coroutine
.running());
83 ok
, err
= pcall(handler
, resolver
:peek(qname
, qtype
, qclass
));
85 log("error", "Error sending DNS query: %s", err
);
86 ok
, err
= pcall(handler
, nil, err
);
89 log("error", "Error in DNS response handler: %s", err
);
91 end)(resolver
:peek(qname
, qtype
, qclass
));
94 function query_methods
:cancel(call_handler
, reason
) -- luacheck: ignore 212/reason
95 log("warn", "Cancelling DNS lookup for %s", self
[4]);
96 self
[1].cancel(self
[2], self
[3], self
[4], self
[5], call_handler
);
99 local function new_async_resolver()
100 local resolver
= new_resolver();
101 resolver
:socket_wrapper_set(new_async_socket
);
102 return setmetatable({ _resolver
= resolver
}, async_resolver_mt
);
106 lookup
= function (...)
107 return new_async_resolver():lookup(...);
109 resolver
= new_async_resolver
;
110 new_async_socket
= new_async_socket
;