kres.lua 15 KB
Newer Older
1 2 3
-- LuaJIT ffi bindings for libkres, a DNS resolver library.
-- @note Since it's statically compiled, it expects to find the symbols in the C namespace.

4 5 6 7 8 9
local ffi_ok, ffi = pcall(require, 'ffi')
if not ffi_ok then
	local M = { error = 'FFI not available, resolver bindings disabled.' }
	setmetatable(M, {__index = function(t,k,v) error(rawget(M, 'error')) end })
	return M
end
10
local bit = require('bit')
11 12 13
local bor = bit.bor
local band = bit.band
local C = ffi.C
14
local knot = ffi.load(libpath('libknot', '2'))
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
ffi.cdef[[

/*
 * Record types and classes.
 */
struct rr_class {
	static const int IN         =   1;
	static const int CH         =   3;
	static const int NONE       = 254;
	static const int ANY        = 255;
};
struct rr_type {
	static const int A          =   1;
	static const int NS         =   2;
	static const int CNAME      =   5;
	static const int SOA        =   6;
	static const int PTR        =  12;
	static const int HINFO      =  13;
	static const int MINFO      =  14;
	static const int MX         =  15;
	static const int TXT        =  16;
	static const int RP         =  17;
	static const int AFSDB      =  18;
	static const int RT         =  21;
	static const int SIG        =  24;
	static const int KEY        =  25;
	static const int AAAA       =  28;
	static const int LOC        =  29;
	static const int SRV        =  33;
	static const int NAPTR      =  35;
	static const int KX         =  36;
	static const int CERT       =  37;
	static const int DNAME      =  39;
	static const int OPT        =  41;
	static const int APL        =  42;
	static const int DS         =  43;
	static const int SSHFP      =  44;
	static const int IPSECKEY   =  45;
	static const int RRSIG      =  46;
	static const int NSEC       =  47;
	static const int DNSKEY     =  48;
	static const int DHCID      =  49;
	static const int NSEC3      =  50;
	static const int NSEC3PARAM =  51;
	static const int TLSA       =  52;
	static const int CDS        =  59;
	static const int CDNSKEY    =  60;
	static const int SPF        =  99;
	static const int NID        = 104;
	static const int L32        = 105;
	static const int L64        = 106;
	static const int LP         = 107;
	static const int EUI48      = 108;
	static const int EUI64      = 109;
	static const int TKEY       = 249;
	static const int TSIG       = 250;
	static const int IXFR       = 251;
	static const int AXFR       = 252;
	static const int ANY        = 255;
};
struct pkt_section {
	static const int ANSWER     = 0;
	static const int AUTHORITY  = 1;
	static const int ADDITIONAL = 2;	
};
struct pkt_rcode {
	static const int NOERROR    =  0;
	static const int FORMERR    =  1;
	static const int SERVFAIL   =  2;
	static const int NXDOMAIN   =  3;
	static const int NOTIMPL    =  4;
	static const int REFUSED    =  5;
	static const int YXDOMAIN   =  6;
	static const int YXRRSET    =  7;
	static const int NXRRSET    =  8;
	static const int NOTAUTH    =  9;
	static const int NOTZONE    = 10;
	static const int BADVERS    = 16;
};
94 95
struct query_flag {
	static const int NO_MINIMIZE = 1 << 0;
96
	static const int NO_THROTTLE = 1 << 1;
97 98
	static const int NO_IPV6     = 1 << 2;
	static const int NO_IPV4     = 1 << 3;
99
	static const int RESOLVED    = 1 << 5;
100
	static const int AWAIT_CUT   = 1 << 8;
101 102 103
	static const int CACHED      = 1 << 10;
	static const int NO_CACHE    = 1 << 11;
	static const int EXPIRING    = 1 << 12;
104
	static const int DNSSEC_WANT = 1 << 14;
105 106
	static const int DNSSEC_BOGUS    = 1 << 15;
	static const int DNSSEC_INSECURE = 1 << 16;
107
	static const int STUB        = 1 << 17;
108
	static const int ALWAYS_CUT  = 1 << 18;
109 110
	static const int PERMISSIVE  = 1 << 20;
	static const int STRICT      = 1 << 21;
111 112
};

113 114 115 116
/*
 * Data structures
 */

117
/* stdlib */
118 119 120 121 122
typedef long time_t;
struct timeval {
	time_t tv_sec;
	time_t tv_usec;
};
123 124 125 126 127
struct sockaddr {
    uint16_t sa_family;
    uint8_t _stub[]; /* Do not touch */
};

128
/* libknot */
129 130 131 132
typedef struct {
	uint8_t _stub[]; /* Do not touch */
} knot_dump_style_t;
extern const knot_dump_style_t KNOT_DUMP_STYLE_DEFAULT;
133 134
typedef int knot_section_t; /* Do not touch */
typedef void knot_rrinfo_t; /* Do not touch */
135
typedef uint8_t knot_dname_t;
136
typedef uint8_t knot_rdata_t;
137 138
typedef struct knot_rdataset {
	uint16_t count;
139
	knot_rdata_t *data;
140 141 142 143 144 145 146
} knot_rdataset_t;
typedef struct knot_rrset {
	knot_dname_t *_owner;
	uint16_t type;
	uint16_t class;
	knot_rdataset_t rr;
} knot_rrset_t;
147 148 149 150 151
typedef struct {
	struct knot_pkt *pkt;
	uint16_t pos;
	uint16_t count;
} knot_pktsection_t;
152 153 154 155 156 157 158 159 160
typedef struct {
	uint8_t *wire;
	size_t size;
	size_t max_size;
	size_t parsed;
	uint16_t reserved;
	uint16_t qname_size;
	uint16_t rrset_count;
	uint16_t flags;
161 162
	knot_rrset_t *opt;
	knot_rrset_t *tsig;
163 164 165 166 167
	knot_section_t _current;
	knot_pktsection_t _sections[3];
	size_t _rrset_allocd;
	knot_rrinfo_t *_rr_info;
	knot_rrset_t *_rr;
168 169 170
	uint8_t _stub[]; /* Do not touch */
} knot_pkt_t;

171 172 173 174 175 176 177 178 179 180
/* generics */
typedef void *(*map_alloc_f)(void *, size_t);
typedef void (*map_free_f)(void *baton, void *ptr);
typedef struct {
	void *root;
	map_alloc_f malloc;
	map_free_f free;
	void *baton;
} map_t;

181
/* libkres */
182 183 184 185 186
typedef struct {
	knot_rrset_t *at;
	size_t len;
	size_t cap;
} rr_array_t;
187 188 189 190 191 192
struct kr_zonecut {
	knot_dname_t *name;
	knot_rrset_t *key;
	knot_rrset_t *trust_anchor;
	uint8_t _stub[]; /* Do not touch */
};
193 194 195 196 197 198
struct kr_query {
	struct kr_query *parent;
	knot_dname_t *sname;
	uint16_t type;
	uint16_t class;
	uint16_t id;
199
	uint32_t flags;
200
	unsigned secret;
201 202
	struct timeval timestamp;
	struct kr_zonecut zone_cut;
203 204 205 206 207 208
	uint8_t _stub[]; /* Do not touch */
};
struct kr_rplan {
	uint8_t _stub[]; /* Do not touch */
};
struct kr_request {
209
	struct kr_context *ctx;
210
	knot_pkt_t *answer;
211
	struct kr_query *current_query;
212 213 214 215
	struct {
		const knot_rrset_t *key;
		const struct sockaddr *addr;
	} qsource;
216 217
	uint32_t options;
	int state;
218 219
	rr_array_t authority;
	rr_array_t additional;
220 221
	uint8_t _stub[]; /* Do not touch */
};
222 223 224 225 226
struct kr_context
{	
	uint32_t options;
	knot_rrset_t *opt_rr;
	map_t trust_anchors;
227
	map_t negative_anchors;
228 229
	uint8_t _stub[]; /* Do not touch */
};
230

231 232
/*
 * libc APIs
233
 */
234
void free(void *ptr);
235
int inet_pton(int af, const char *src, void *dst);
236

237 238 239
/*
 * libknot APIs
 */
240
/* Domain names */
241
int knot_dname_size(const knot_dname_t *name);
242 243
knot_dname_t *knot_dname_from_str(uint8_t *dst, const char *name, size_t maxlen);
char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen);
244
/* Resource records */
245 246 247 248
uint16_t knot_rdata_rdlen(const knot_rdata_t *rr);
uint8_t *knot_rdata_data(const knot_rdata_t *rr);
knot_rdata_t *knot_rdataset_at(const knot_rdataset_t *rrs, size_t pos);
uint32_t knot_rrset_ttl(const knot_rrset_t *rrset);
249 250 251
int knot_rrset_txt_dump_data(const knot_rrset_t *rrset, size_t pos, char *dst, size_t maxlen, const knot_dump_style_t *style);
int knot_rrset_txt_dump(const knot_rrset_t *rrset, char *dst, size_t maxlen, const knot_dump_style_t *style);

252 253 254 255 256 257
/* Packet */
const knot_dname_t *knot_pkt_qname(const knot_pkt_t *pkt);
uint16_t knot_pkt_qtype(const knot_pkt_t *pkt);
uint16_t knot_pkt_qclass(const knot_pkt_t *pkt);
int knot_pkt_begin(knot_pkt_t *pkt, int section_id);
int knot_pkt_put_question(knot_pkt_t *pkt, const knot_dname_t *qname, uint16_t qclass, uint16_t qtype);
258
const knot_rrset_t *knot_pkt_rr(const knot_pktsection_t *section, uint16_t i);
259 260
const knot_pktsection_t *knot_pkt_section(const knot_pkt_t *pkt,
                                          knot_section_t section_id);
261

262 263
/* 
 * libkres API
264 265 266
 */
/* Resolution request */
struct kr_rplan *kr_resolve_plan(struct kr_request *request);
267
void *kr_resolve_pool(struct kr_request *request);
268
/* Resolution plan */
269 270
struct kr_query *kr_rplan_push(struct kr_rplan *rplan, struct kr_query *parent,
                               const knot_dname_t *name, uint16_t cls, uint16_t type);
271 272
struct kr_query *kr_rplan_resolved(struct kr_rplan *rplan);
struct kr_query *kr_rplan_next(struct kr_query *qry);
273 274
/* Nameservers */
int kr_nsrep_set(struct kr_query *qry, uint8_t *addr, size_t addr_len);
275 276 277 278 279
/* Query */
/* Utils */
unsigned kr_rand_uint(unsigned max);
int kr_pkt_put(knot_pkt_t *pkt, const knot_dname_t *name, uint32_t ttl,
               uint16_t rclass, uint16_t rtype, const uint8_t *rdata, uint16_t rdlen);
280
int kr_pkt_recycle(knot_pkt_t *pkt);
281
const char *kr_inaddr(const struct sockaddr *addr);
282
int kr_inaddr_family(const struct sockaddr *addr);
283
int kr_inaddr_len(const struct sockaddr *addr);
284
int kr_straddr_family(const char *addr);
285 286
int kr_straddr_subnet(void *dst, const char *addr);
int kr_bitcmp(const char *a, const char *b, int bits);
287 288
int kr_family_len(int family);
int kr_rrarray_add(rr_array_t *array, const knot_rrset_t *rr, void *pool);
289 290 291 292 293 294 295 296 297 298 299 300
/* Trust anchors */
knot_rrset_t *kr_ta_get(map_t *trust_anchors, const knot_dname_t *name);
int kr_ta_add(map_t *trust_anchors, const knot_dname_t *name, uint16_t type,
               uint32_t ttl, const uint8_t *rdata, uint16_t rdlen);
int kr_ta_del(map_t *trust_anchors, const knot_dname_t *name);
void kr_ta_clear(map_t *trust_anchors);
/* DNSSEC */
bool kr_dnssec_key_ksk(const uint8_t *dnskey_rdata);
bool kr_dnssec_key_revoked(const uint8_t *dnskey_rdata);
int kr_dnssec_key_tag(uint16_t rrtype, const uint8_t *rdata, size_t rdlen);
int kr_dnssec_key_match(const uint8_t *key_a_rdata, size_t key_a_rdlen,
                        const uint8_t *key_b_rdata, size_t key_b_rdlen);
301 302
]]

303
-- Metatype for sockaddr
304
local addr_buf = ffi.new('char[16]')
305 306 307 308
local sockaddr_t = ffi.typeof('struct sockaddr')
ffi.metatype( sockaddr_t, {
	__index = {
		len = function(sa) return C.kr_inaddr_len(sa) end,
309
		ip = function (sa) return C.kr_inaddr(sa) end,
310
		family = function (sa) return C.kr_inaddr_family(sa) end,
311 312 313 314
	}
})

-- Metatype for RR set
315 316
local rrset_buflen = (64 + 1) * 1024
local rrset_buf = ffi.new('char[?]', rrset_buflen)
317 318 319
local knot_rrset_t = ffi.typeof('knot_rrset_t')
ffi.metatype( knot_rrset_t, {
	__index = {
320 321 322 323 324 325 326 327 328 329 330 331 332
		owner = function(rr) return ffi.string(rr._owner, knot.knot_dname_size(rr._owner)) end,
		ttl = function(rr) return tonumber(knot.knot_rrset_ttl(rr)) end,
		rdata = function(rr, i)
			local rdata = knot.knot_rdataset_at(rr.rr, i)
			return ffi.string(knot.knot_rdata_data(rdata), knot.knot_rdata_rdlen(rdata))
		end,
		get = function(rr, i)
			return {owner = rr:owner(),
			        ttl = rr:ttl(),
			        class = tonumber(rr.class),
			        type = tonumber(rr.type),
			        rdata = rr:rdata(i)}
		end,
333 334 335 336 337 338 339 340 341 342 343 344
		tostring = function(rr, i)
			assert(ffi.istype(knot_rrset_t, rr))
			if rr.rr.count > 0 then
				local ret = -1
				if i ~= nil then
					ret = knot.knot_rrset_txt_dump_data(rr, i, rrset_buf, rrset_buflen, knot.KNOT_DUMP_STYLE_DEFAULT)
				else
					ret = knot.knot_rrset_txt_dump(rr, rrset_buf, rrset_buflen, knot.KNOT_DUMP_STYLE_DEFAULT)
				end
				return ret >= 0 and ffi.string(rrset_buf)
			end
		end,
345 346 347
	}
})

348 349 350 351
-- Metatype for packet
local knot_pkt_t = ffi.typeof('knot_pkt_t')
ffi.metatype( knot_pkt_t, {
	__index = {
352 353 354 355
		qname = function(pkt)
			local qname = knot.knot_pkt_qname(pkt)
			return ffi.string(qname, knot.knot_dname_size(qname))
		end,
356 357 358
		qclass = function(pkt) return knot.knot_pkt_qclass(pkt) end,
		qtype  = function(pkt) return knot.knot_pkt_qtype(pkt) end,
		rcode = function (pkt, val)
359 360 361 362 363 364
			pkt.wire[3] = (val) and bor(band(pkt.wire[3], 0xf0), val) or pkt.wire[3]
			return band(pkt.wire[3], 0x0f)
		end,
		tc = function (pkt, val)
			pkt.wire[2] = bor(pkt.wire[2], (val) and 0x02 or 0x00)
			return band(pkt.wire[2], 0x02)
365
		end,
366 367 368 369 370 371 372 373 374
		rrsets = function (pkt, section_id)
			local records = {}
			local section = knot.knot_pkt_section(pkt, section_id)
			for i = 1, section.count do
				local rrset = knot.knot_pkt_rr(section, i - 1)
				table.insert(records, rrset)
			end
			return records
		end,
375 376
		section = function (pkt, section_id)
			local records = {}
377
			local section = knot.knot_pkt_section(pkt, section_id)
378 379 380 381
			for i = 1, section.count do
				local rrset = knot.knot_pkt_rr(section, i - 1)
				for k = 1, rrset.rr.count do
					table.insert(records, rrset:get(k - 1))
382 383 384 385
				end
			end
			return records
		end, 
386 387
		begin = function (pkt, section) return knot.knot_pkt_begin(pkt, section) end,
		put = function (pkt, owner, ttl, rclass, rtype, rdata)
388
			return C.kr_pkt_put(pkt, owner, ttl, rclass, rtype, rdata, #rdata)
389 390 391 392 393
		end,
		clear = function (pkt) return C.kr_pkt_recycle(pkt) end,
		question = function(pkt, qname, qclass, qtype)
			return C.knot_pkt_put_question(pkt, qname, qclass, qtype)
		end,
394 395 396
	},
})
-- Metatype for query
397
local ub_t = ffi.typeof('unsigned char *')
398 399 400
local kr_query_t = ffi.typeof('struct kr_query')
ffi.metatype( kr_query_t, {
	__index = {
401
		name = function(qry, new_name) return ffi.string(qry.sname, knot.knot_dname_size(qry.sname)) end,
402 403 404
		hasflag = function(qry, flag)
			return band(qry.flags, flag) ~= 0
		end,
405
		resolved = function(qry)
406
			return qry:hasflag(kres.query.RESOLVED)
407 408 409 410
		end,
		final = function(qry)
			return qry:resolved() and (qry.parent == nil)
		end,
411 412 413 414
		nslist = function(qry, ns)
			if ns ~= nil then C.kr_nsrep_set(qry, ffi.cast(ub_t, ns), #ns) end
			-- @todo: Return list of NS entries, not possible ATM because the NSLIST is union and missing typedef
		end,
415 416 417 418 419 420 421 422
	},
})
-- Metatype for request
local kr_request_t = ffi.typeof('struct kr_request')
ffi.metatype( kr_request_t, {
	__index = {
		current = function(req)
			assert(req)
423
			if req.current_query == nil then return nil end
424
			return req.current_query
425
		end,
426 427
		resolved = function(req)
			assert(req)
428 429 430 431
			qry = C.kr_rplan_resolved(C.kr_resolve_plan(req))
			if qry == nil then return nil end
			return qry

432
		end,
433 434 435 436 437 438 439 440 441
		push = function(req, qname, qtype, qclass, flags, parent)
			assert(req)
			local rplan = C.kr_resolve_plan(req)
			local qry = C.kr_rplan_push(rplan, parent, qname, qclass, qtype)
			if qry ~= nil and flags ~= nil then
				qry.flags = bor(qry.flags, flags)
			end
			return qry
		end,
442 443 444 445
		pop = function(req, qry)
			assert(req)
			return C.kr_rplan_pop(C.kr_resolve_plan(req), qry)
		end,
446 447 448
	},
})

449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
-- Pretty print for domain name
local function dname2str(dname)
	return ffi.string(ffi.gc(C.knot_dname_to_str(nil, dname, 0), C.free))
end

-- Pretty print for RR
local function rr2str(rr)
	local function hex_encode(str)
		return (str:gsub('.', function (c)
			return string.format('%02X', string.byte(c))
		end))
	end
	local rdata = hex_encode(rr.rdata)
	return string.format('%s %d IN TYPE%d \\# %d %s',
		dname2str(rr.owner), rr.ttl, rr.type, #rr.rdata, rdata)
end


467 468 469 470 471 472 473
-- Module API
local kres = {
	-- Constants
	class = ffi.new('struct rr_class'),
	type = ffi.new('struct rr_type'),
	section = ffi.new('struct pkt_section'),
	rcode = ffi.new('struct pkt_rcode'),
474
	query = ffi.new('struct query_flag'),
475
	NOOP = 0, YIELD = 0, CONSUME = 1, PRODUCE = 2, DONE = 4, FAIL = 8,
476 477 478 479
	-- Metatypes
	pkt_t = function (udata) return ffi.cast('knot_pkt_t *', udata) end,
	request_t = function (udata) return ffi.cast('struct kr_request *', udata) end,
	-- Global API functions
480 481 482 483
	str2dname = function(name)
		local dname = ffi.gc(C.knot_dname_from_str(nil, name, 0), C.free)
		return ffi.string(dname, knot.knot_dname_size(dname))
	end,
484 485
	dname2str = dname2str,
	rr2str = rr2str,
486 487
	str2ip = function (ip)
		local family = C.kr_straddr_family(ip)
488
		local ret = C.inet_pton(family, ip, addr_buf)
489
		if ret ~= 1 then return nil end
490
		return ffi.string(addr_buf, C.kr_family_len(family))
491
	end,
492
	context = function () return ffi.cast('struct kr_context *', __engine) end,
493 494
}

495
return kres