comparison net/unbound.lua @ 14210:41fa97090264

Merge 13.0->trunk
author Kim Alvefur <zash@zash.se>
date Sat, 30 May 2026 19:22:51 +0200
parents 350e16e5f9aa c4aa9b2b4787
children 2719dbb358c8
comparison
equal deleted inserted replaced
14206:2b13c24ba2d6 14210:41fa97090264
17 local log = logger.init("unbound"); 17 local log = logger.init("unbound");
18 local net_server = require "prosody.net.server"; 18 local net_server = require "prosody.net.server";
19 local libunbound = require"lunbound"; 19 local libunbound = require"lunbound";
20 local promise = require"prosody.util.promise"; 20 local promise = require"prosody.util.promise";
21 local new_id = require "prosody.util.id".short; 21 local new_id = require "prosody.util.id".short;
22 local timer = require "prosody.util.timer";
22 23
23 local dns_utils = require"prosody.util.dns"; 24 local dns_utils = require"prosody.util.dns";
24 local classes, types, errors = dns_utils.classes, dns_utils.types, dns_utils.errors; 25 local classes, types, errors = dns_utils.classes, dns_utils.types, dns_utils.errors;
25 local parsers = dns_utils.parsers; 26 local parsers = dns_utils.parsers;
26 27
40 end 41 end
41 return conf; 42 return conf;
42 end 43 end
43 44
44 local unbound_config; 45 local unbound_config;
45 if prosody then
46 local config = require"prosody.core.configmanager";
47 unbound_config = add_defaults(config.get("*", "unbound"));
48 prosody.events.add_handler("config-reloaded", function()
49 unbound_config = add_defaults(config.get("*", "unbound"));
50 end);
51 end
52 -- Note: libunbound will default to using root hints if resolvconf is unset 46 -- Note: libunbound will default to using root hints if resolvconf is unset
53 47
54 local function connect_server(unbound, server) 48 local function connect_server(unbound, server)
55 log("debug", "Setting up net.server event handling for %s", unbound); 49 log("debug", "Setting up net.server event handling for %s", unbound);
56 return server.watchfd(unbound, function () 50 return server.watchfd(unbound, function ()
62 local unbound, server_conn; 56 local unbound, server_conn;
63 57
64 local function initialize() 58 local function initialize()
65 unbound = libunbound.new(unbound_config); 59 unbound = libunbound.new(unbound_config);
66 server_conn = connect_server(unbound, net_server); 60 server_conn = connect_server(unbound, net_server);
67 end
68 if prosody then
69 prosody.events.add_handler("server-started", initialize);
70 end 61 end
71 62
72 local answer_mt = { 63 local answer_mt = {
73 __tostring = function(self) 64 __tostring = function(self)
74 if self._string then return self._string end 65 if self._string then return self._string end
89 local _string = t_concat(t, "\n"); 80 local _string = t_concat(t, "\n");
90 self._string = _string; 81 self._string = _string;
91 return _string; 82 return _string;
92 end; 83 end;
93 }; 84 };
94
95 local waiting_queries = {};
96 85
97 local function prep_answer(a) 86 local function prep_answer(a)
98 if not a then return end 87 if not a then return end
99 local status = errors[a.rcode]; 88 local status = errors[a.rcode];
100 local qclass = classes[a.qclass]; 89 local qclass = classes[a.qclass];
126 qtype = qtype and s_upper(qtype) or "A"; 115 qtype = qtype and s_upper(qtype) or "A";
127 qclass = qclass and s_upper(qclass) or "IN"; 116 qclass = qclass and s_upper(qclass) or "IN";
128 local ntype, nclass = types[qtype], classes[qclass]; 117 local ntype, nclass = types[qtype], classes[qclass];
129 118
130 local m; 119 local m;
131 local ret;
132 local log_query = logger.init("unbound.query"..new_id()); 120 local log_query = logger.init("unbound.query"..new_id());
133 local function callback_wrapper(a, err) 121 local function callback_wrapper(a, err)
134 m(); 122 m();
135 waiting_queries[ret] = nil;
136 if a then 123 if a then
137 count(qclass, qtype, #a); 124 count(qclass, qtype, #a);
138 prep_answer(a); 125 prep_answer(a);
139 log_query("debug", "Results for %s %s %s: %s (%s)", qname, qclass, qtype, a.rcode == 0 and (#a .. " items") or a.status, 126 log_query("debug", "Results for %s %s %s: %s (%s)", qname, qclass, qtype, a.rcode == 0 and (#a .. " items") or a.status,
140 a.secure and "Secure" or a.bogus or "Insecure"); -- Insecure as in unsigned 127 a.secure and "Secure" or a.bogus or "Insecure"); -- Insecure as in unsigned
144 local ok, cerr = pcall(callback, a, err); 131 local ok, cerr = pcall(callback, a, err);
145 if not ok then log_query("error", "Error in callback: %s", cerr); end 132 if not ok then log_query("error", "Error in callback: %s", cerr); end
146 end 133 end
147 log_query("debug", "Resolve %s %s %s", qname, qclass, qtype); 134 log_query("debug", "Resolve %s %s %s", qname, qclass, qtype);
148 m = measure(qclass, qtype); 135 m = measure(qclass, qtype);
149 local err; 136 local ret, err = unbound:resolve_async(callback_wrapper, qname, ntype, nclass);
150 ret, err = unbound:resolve_async(callback_wrapper, qname, ntype, nclass); 137 if not ret then
151 if ret then
152 waiting_queries[ret] = callback;
153 else
154 log_query("error", "Resolver error: %s", err); 138 log_query("error", "Resolver error: %s", err);
155 end 139 end
156 return ret, err; 140 return ret, err;
157 end 141 end
158 142
164 local a, err = unbound:resolve(qname, ntype, nclass); 148 local a, err = unbound:resolve(qname, ntype, nclass);
165 if not a then return a, err; end 149 if not a then return a, err; end
166 return prep_answer(a); 150 return prep_answer(a);
167 end 151 end
168 152
169 local function cancel(id)
170 local cb = waiting_queries[id];
171 unbound:cancel(id);
172 if cb then
173 cb(nil, "canceled");
174 waiting_queries[id] = nil;
175 end
176 return true;
177 end
178
179 -- Reinitiate libunbound context, drops cache 153 -- Reinitiate libunbound context, drops cache
180 local function purge() 154 local function purge()
181 for id in pairs(waiting_queries) do cancel(id); end 155 if server_conn then
182 if server_conn then server_conn:close(); end 156 local old_unbound, old_server_conn = unbound, server_conn;
157 timer.add_task(30, function()
158 old_server_conn:close();
159 if old_unbound.cancelall then
160 old_unbound:cancelall();
161 end
162 end)
163 end
183 initialize(); 164 initialize();
184 return true; 165 return true;
166 end
167
168 if prosody then
169 local config = require"prosody.core.configmanager";
170 unbound_config = add_defaults(config.get("*", "unbound"));
171 prosody.events.add_handler("config-reloaded", function()
172 unbound_config = add_defaults(config.get("*", "unbound"));
173 purge();
174 end);
175 prosody.events.add_handler("server-started", initialize);
185 end 176 end
186 177
187 local function not_implemented() 178 local function not_implemented()
188 error "not implemented"; 179 error "not implemented";
189 end 180 end
190 -- Public API 181 -- Public API
191 local _M = { 182 local _M = {
192 lookup = lookup; 183 lookup = lookup;
193 cancel = cancel; 184 cancel = not_implemented;
194 new_async_socket = not_implemented; 185 new_async_socket = not_implemented;
195 dns = { 186 dns = {
196 lookup = lookup_sync; 187 lookup = lookup_sync;
197 cancel = cancel; 188 cancel = not_implemented;
198 cache = noop; 189 cache = noop;
199 socket_wrapper_set = noop; 190 socket_wrapper_set = noop;
200 settimeout = noop; 191 settimeout = noop;
201 query = noop; 192 query = noop;
202 purge = purge; 193 purge = purge;