engine.c 26.7 KB
Newer Older
1
/*  Copyright (C) 2015-2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 3 4 5 6 7 8 9 10 11 12 13

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
14
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
15 16
 */

17
#include <contrib/cleanup.h>
18
#include <ccan/json/json.h>
19
#include <ccan/asprintf/asprintf.h>
20 21
#include <uv.h>
#include <unistd.h>
22 23
#include <grp.h>
#include <pwd.h>
24
#include <sys/param.h>
Vladimír Čunát's avatar
Vladimír Čunát committed
25
#include <libzscanner/scanner.h>
26 27

#include "daemon/engine.h"
28
#include "daemon/bindings.h"
29
#include "daemon/ffimodule.h"
30
#include "lib/nsrep.h"
31
#include "lib/cache/api.h"
32
#include "lib/defines.h"
33
#include "lib/cache/cdb_lmdb.h"
34
#include "lib/dnssec/ta.h"
35

36 37 38 39 40
/** @internal Compatibility wrapper for Lua < 5.2 */
#if LUA_VERSION_NUM < 502
#define lua_rawlen(L, obj) lua_objlen((L), (obj))
#endif

41 42 43
/** @internal Annotate for static checkers. */
KR_NORETURN int lua_error (lua_State *L);

44 45 46
/* Cleanup engine state every 5 minutes */
const size_t CLEANUP_TIMER = 5*60*1000;

47 48 49 50 51 52 53
/* Execute byte code */
#define l_dobytecode(L, arr, len, name) \
	(luaL_loadbuffer((L), (arr), (len), (name)) || lua_pcall((L), 0, LUA_MULTRET, 0))
/** Load file in a sandbox environment. */
#define l_dosandboxfile(L, filename) \
	(luaL_loadfile((L), (filename)) || engine_pcall((L), 0))

54 55 56 57
/*
 * Global bindings.
 */

58
/** Register module callback into Lua world. */
59
#define REGISTER_MODULE_CALL(L, module, cb, name) do { \
60 61 62
	lua_pushlightuserdata((L), (module)); \
	lua_pushlightuserdata((L), (cb)); \
	lua_pushcclosure((L), l_trampoline, 2); \
63 64
	lua_setfield((L), -2, (name)); \
	} while (0)
65

66 67 68
/** Print help and available commands. */
static int l_help(lua_State *L)
{
69
	static const char *help_str =
70 71
		"help()\n    show this help\n"
		"quit()\n    quit\n"
72
		"hostname()\n    hostname\n"
73
		"package_version()\n    return package version\n"
74
		"user(name[, group])\n    change process user (and group)\n"
75
		"verbose(true|false)\n    toggle verbose mode\n"
76
		"option(opt[, new_val])\n    get/set server option\n"
77
		"mode(strict|normal|permissive)\n    set resolver strictness level\n"
78
		"reorder_RR([true|false])\n    set/get reordering of RRs within RRsets\n"
79 80
		"resolve(name, type[, class, flags, callback])\n    resolve query, callback when it's finished\n"
		"todname(name)\n    convert name to wire format\n"
81
		"tojson(val)\n    convert value to JSON\n"
82
		"map(expr)\n    run expression on all workers\n"
83 84 85 86
		"net\n    network configuration\n"
		"cache\n    network configuration\n"
		"modules\n    modules configuration\n"
		"kres\n    resolver services\n"
87
		"trust_anchors\n    configure trust anchors\n"
88
		;
89 90
	lua_pushstring(L, help_str);
	return 1;
91 92
}

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
static bool update_privileges(int uid, int gid)
{
	if ((gid_t)gid != getgid()) {
		if (setregid(gid, gid) < 0) {
			return false;
		}
	}
	if ((uid_t)uid != getuid()) {
		if (setreuid(uid, uid) < 0) {
			return false;
		}
	}
	return true;
}

/** Set process user/group. */
static int l_setuser(lua_State *L)
{
	int n = lua_gettop(L);
	if (n < 1 || !lua_isstring(L, 1)) {
		lua_pushliteral(L, "user(user[, group)");
		lua_error(L);
	}
	/* Fetch UID/GID based on string identifiers. */
	struct passwd *user_pw = getpwnam(lua_tostring(L, 1));
	if (!user_pw) {
		lua_pushliteral(L, "invalid user name");
		lua_error(L);
	}
	int uid = user_pw->pw_uid;
	int gid = getgid();
	if (n > 1 && lua_isstring(L, 2)) {
		struct group *group_pw = getgrnam(lua_tostring(L, 2));
		if (!group_pw) {
			lua_pushliteral(L, "invalid group name");
			lua_error(L);
		}
		gid = group_pw->gr_gid;
	}
	/* Drop privileges */
	bool ret = update_privileges(uid, gid);
	if (!ret) {
		lua_pushstring(L, strerror(errno));
		lua_error(L);
	}
	lua_pushboolean(L, ret);
	return 1;
}

142 143 144 145 146 147 148
/** Quit current executable. */
static int l_quit(lua_State *L)
{
	engine_stop(engine_luaget(L));
	return 0;
}

149 150 151 152
/** Toggle verbose mode. */
static int l_verbose(lua_State *L)
{
	if (lua_isboolean(L, 1) || lua_isnumber(L, 1)) {
153
		kr_verbose_set(lua_toboolean(L, 1));
154
	}
155
	lua_pushboolean(L, kr_verbose_status);
156 157 158
	return 1;
}

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
char *engine_get_hostname(struct engine *engine) {
	static char hostname_str[KNOT_DNAME_MAXLEN];
	if (!engine) {
		return NULL;
	}

	if (!engine->hostname) {
		if (gethostname(hostname_str, sizeof(hostname_str)) != 0)
			return NULL;
		return hostname_str;
	}
	return engine->hostname;
}

int engine_set_hostname(struct engine *engine, const char *hostname) {
	if (!engine || !hostname) {
		return kr_error(EINVAL);
	}

	char *new_hostname = strdup(hostname);
	if (!new_hostname) {
		return kr_error(ENOMEM);
	}
	if (engine->hostname) {
		free(engine->hostname);
	}
	engine->hostname = new_hostname;
186
	network_new_hostname(&engine->net, engine);
187 188 189 190

	return 0;
}

191 192 193
/** Return hostname. */
static int l_hostname(lua_State *L)
{
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
	struct engine *engine = engine_luaget(L);
	if (lua_gettop(L) == 0) {
		lua_pushstring(L, engine_get_hostname(engine));
		return 1;
	}
	if ((lua_gettop(L) != 1) || !lua_isstring(L, 1)) {
		lua_pushstring(L, "hostname takes at most one parameter: (\"fqdn\")");
		lua_error(L);
	}

	if (engine_set_hostname(engine, lua_tostring(L, 1)) != 0) {
		lua_pushstring(L, "setting hostname failed");
		lua_error(L);
	}

	lua_pushstring(L, engine_get_hostname(engine));	
210 211 212
	return 1;
}

213 214 215 216 217 218 219
/** Return server package version. */
static int l_package_version(lua_State *L)
{
	lua_pushliteral(L, PACKAGE_VERSION);
	return 1;
}

220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
char *engine_get_moduledir(struct engine *engine) {
	return engine->moduledir;
}

int engine_set_moduledir(struct engine *engine, const char *moduledir) {
	if (!engine || !moduledir) {
		return kr_error(EINVAL);
	}

	char *new_moduledir = strdup(moduledir);
	if (!new_moduledir) {
		return kr_error(ENOMEM);
	}
	if (engine->moduledir) {
		free(engine->moduledir);
	}
	engine->moduledir = new_moduledir;

	/* Use module path for including Lua scripts */
	char l_paths[MAXPATHLEN] = { 0 };
	/* Save original package.path to package._path */
	snprintf(l_paths, MAXPATHLEN - 1,
		 "if package._path == nil then package._path = package.path end\n"
243 244
		 "package.path = '%1$s/?.lua;%1$s/?/init.lua;'..package._path\n"
		 "if package._cpath == nil then package._cpath = package.cpath end\n"
245 246
		 "package.cpath = '%1$s/?%2$s;'..package._cpath\n",
		 new_moduledir, LIBEXT);
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277

	int ret = l_dobytecode(engine->L, l_paths, strlen(l_paths), "");
	if (ret != 0) {
		lua_pop(engine->L, 1);
		return ret;
	}
	return 0;
}

/** Return hostname. */
static int l_moduledir(lua_State *L)
{
	struct engine *engine = engine_luaget(L);
	if (lua_gettop(L) == 0) {
		lua_pushstring(L, engine_get_moduledir(engine));
		return 1;
	}
	if ((lua_gettop(L) != 1) || !lua_isstring(L, 1)) {
		lua_pushstring(L, "moduledir takes at most one parameter: (\"directory\")");
		lua_error(L);
	}

	if (engine_set_moduledir(engine, lua_tostring(L, 1)) != 0) {
		lua_pushstring(L, "setting moduledir failed");
		lua_error(L);
	}

	lua_pushstring(L, engine_get_moduledir(engine));
	return 1;
}

278 279 280 281 282 283 284 285 286
/** @internal for l_trustanchor: */
static void ta_add(zs_scanner_t *zs)
{
	map_t *ta = zs->process.data;
	if (!ta)
		return;
	if (kr_ta_add(ta, zs->r_owner, zs->r_type, zs->r_ttl, zs->r_data, zs->r_data_length))
		zs->process.data = NULL; /* error signalling */
}
287 288 289 290 291 292
/** Enable/disable trust anchor. */
static int l_trustanchor(lua_State *L)
{
	struct engine *engine = engine_luaget(L);
	const char *anchor = lua_tostring(L, 1);
	bool enable = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : true;
293
	if (!anchor || strlen(anchor) == 0) {
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
		return 0;
	}
	/* If disabling, parse the owner string only. */
	if (!enable) {
		knot_dname_t *owner = knot_dname_from_str(NULL, anchor, KNOT_DNAME_MAXLEN);
		if (!owner) {
			lua_pushstring(L, "invalid trust anchor owner");
			lua_error(L);
		}
		lua_pushboolean(L, kr_ta_del(&engine->resolver.trust_anchors, owner) == 0);
		free(owner);
		return 1;
	}

	/* Parse the record */
	zs_scanner_t *zs = malloc(sizeof(*zs));
	if (!zs || zs_init(zs, ".", 1, 0) != 0) {
		free(zs);
		lua_pushstring(L, "not enough memory");
		lua_error(L);
	}
315 316 317 318 319
	zs_set_processing(zs, ta_add, NULL, &engine->resolver.trust_anchors);
	bool ok = zs_set_input_string(zs, anchor, strlen(anchor)) == 0
		&& zs_parse_all(zs) == 0;
	ok = ok && zs->process.data; /* reset to NULL on error in ta_add */

320 321 322 323 324 325 326 327 328 329
	zs_deinit(zs);
	free(zs);
	/* Report errors */
	if (!ok) {
		lua_pushstring(L, "failed to process trust anchor RR");
		lua_error(L);
	}
	lua_pushboolean(L, true);
	return 1;
}
330 331

/** Load root hints from zonefile. */
332
static int l_hint_root_file(lua_State *L)
333 334 335 336 337
{
	struct engine *engine = engine_luaget(L);
	struct kr_context *ctx = &engine->resolver;
	const char *file = lua_tostring(L, 1);

338
	const char *err = engine_hint_root_file(ctx, file);
339
	if (err) {
340 341 342 343
		if (!file) {
			file = ROOTHINTS;
		}
		lua_push_printf(L, "error when opening '%s': %s", file, err);
344
		lua_error(L);
345 346 347
	} else {
		lua_pushboolean(L, true);
		return 1;
348
	}
349 350
}

351 352 353 354 355 356 357 358 359
/** @internal for engine_hint_root_file */
static void roothints_add(zs_scanner_t *zs)
{
	struct kr_zonecut *hints = zs->process.data;
	if (!hints) {
		return;
	}
	if (zs->r_type == KNOT_RRTYPE_A || zs->r_type == KNOT_RRTYPE_AAAA) {
		knot_rdata_t rdata[RDATA_ARR_MAX];
360
		knot_rdata_init(rdata, zs->r_data_length, zs->r_data);
361 362 363 364
		kr_zonecut_add(hints, zs->r_owner, rdata);
	}
}
const char* engine_hint_root_file(struct kr_context *ctx, const char *file)
365 366 367 368 369 370 371 372 373 374 375 376
{
	if (!file) {
		file = ROOTHINTS;
	}
	if (strlen(file) == 0 || !ctx) {
		return "invalid parameters";
	}
	struct kr_zonecut *root_hints = &ctx->root_hints;

	zs_scanner_t zs;
	if (zs_init(&zs, ".", 1, 0) != 0) {
		return "not enough memory";
377
	}
378
	if (zs_set_input_file(&zs, file) != 0) {
379
		zs_deinit(&zs);
380 381 382
		return "failed to open root hints file";
	}

383
	kr_zonecut_set(root_hints, (const uint8_t *)"");
384 385
	zs_set_processing(&zs, roothints_add, NULL, root_hints);
	zs_parse_all(&zs);
386
	zs_deinit(&zs);
387
	return NULL;
388
}
389

390 391 392
/** Unpack JSON object to table */
static void l_unpack_json(lua_State *L, JsonNode *table)
{
393 394 395 396 397 398 399 400
	/* Unpack POD */
	switch(table->tag) {
		case JSON_STRING: lua_pushstring(L, table->string_); return;
		case JSON_NUMBER: lua_pushnumber(L, table->number_); return;
		case JSON_BOOL:   lua_pushboolean(L, table->bool_); return;
		default: break;
	}
	/* Unpack object or array into table */
401 402 403 404 405 406 407 408 409
	lua_newtable(L);
	JsonNode *node = NULL;
	json_foreach(node, table) {
		/* Push node value */
		switch(node->tag) {
		case JSON_OBJECT: /* as array */
		case JSON_ARRAY:  l_unpack_json(L, node); break;
		case JSON_STRING: lua_pushstring(L, node->string_); break;
		case JSON_NUMBER: lua_pushnumber(L, node->number_); break;
410
		case JSON_BOOL:   lua_pushboolean(L, node->bool_); break;
411 412 413 414 415 416 417 418 419 420 421
		default: continue;
		}
		/* Set table key */
		if (node->key) {
			lua_setfield(L, -2, node->key);
		} else {
			lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
		}
	}
}

422
/** @internal Recursive Lua/JSON serialization. */
423 424
static JsonNode *l_pack_elem(lua_State *L, int top)
{
425 426 427 428 429 430
	switch(lua_type(L, top)) {
	case LUA_TSTRING:  return json_mkstring(lua_tostring(L, top));
	case LUA_TNUMBER:  return json_mknumber(lua_tonumber(L, top));
	case LUA_TBOOLEAN: return json_mkbool(lua_toboolean(L, top));
	case LUA_TTABLE:   break; /* Table, iterate it. */
	default:           return json_mknull();
431
	}
432 433 434 435
	/* Use absolute indexes here, as the table may be nested. */
	JsonNode *node = NULL;
	lua_pushnil(L);
	while(lua_next(L, top) != 0) {
436
		bool is_array = false;
437
		if (!node) {
438
			is_array = (lua_type(L, top + 1) == LUA_TNUMBER);
439
			node = is_array ? json_mkarray() : json_mkobject();
440 441 442
			if (!node) {
				return NULL;
			}
443 444
		} else {
			is_array = node->tag == JSON_ARRAY;
445
		}
446

447 448 449
		/* Insert to array/table. */
		JsonNode *val = l_pack_elem(L, top + 2);
		if (is_array) {
450 451
			json_append_element(node, val);
		} else {
452 453
			const char *key = lua_tostring(L, top + 1);
			json_append_member(node, key, val);
454 455
		}
		lua_pop(L, 1);
456
	}
457 458
	/* Return empty object for empty tables. */
	return node ? node : json_mkobject();
459 460
}

461
/** @internal Serialize to string */
462 463
static char *l_pack_json(lua_State *L, int top)
{
464
	JsonNode *root = l_pack_elem(L, top);
465 466 467 468 469 470 471 472
	if (!root) {
		return NULL;
	}
	char *result = json_encode(root);
	json_delete(root);
	return result;
}

473 474
static int l_tojson(lua_State *L)
{
475
	auto_free char *json_str = l_pack_json(L, lua_gettop(L));
476 477 478 479 480 481 482
	if (!json_str) {
		return 0;
	}
	lua_pushstring(L, json_str);
	return 1;
}

483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
static int l_fromjson(lua_State *L)
{
	if (lua_gettop(L) != 1 || !lua_isstring(L, 1)) {
		lua_pushliteral(L, "a JSON string is required");
		lua_error(L);
	}

	const char *json_str = lua_tostring(L, 1);
	JsonNode *root_node = json_decode(json_str);

	if (!root_node) {
		lua_pushliteral(L, "invalid JSON string");
		lua_error(L);
	}
	l_unpack_json(L, root_node);
	json_delete(root_node);

	return 1;
}

503 504 505 506 507 508
/** @internal Throw Lua error if expr is false */
#define expr_checked(expr) \
	if (!(expr)) { lua_pushboolean(L, false); lua_rawseti(L, -2, lua_rawlen(L, -2) + 1); continue; }

static int l_map(lua_State *L)
{
509 510 511 512 513
	if (lua_gettop(L) != 1 || !lua_isstring(L, 1)) {
		lua_pushliteral(L, "map('string with a lua expression')");
		lua_error(L);
	}

514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
	struct engine *engine = engine_luaget(L);
	const char *cmd = lua_tostring(L, 1);
	uint32_t len = strlen(cmd);
	lua_newtable(L);

	/* Execute on leader instance */
	int ntop = lua_gettop(L);
	engine_cmd(L, cmd, true);
	lua_settop(L, ntop + 1); /* Push only one return value to table */
	lua_rawseti(L, -2, 1);

	for (size_t i = 0; i < engine->ipc_set.len; ++i) {
		int fd = engine->ipc_set.at[i];
		/* Send command */
		expr_checked(write(fd, &len, sizeof(len)) == sizeof(len));
		expr_checked(write(fd, cmd, len) == len);
		/* Read response */
		uint32_t rlen = 0;
		if (read(fd, &rlen, sizeof(rlen)) == sizeof(rlen)) {
533
			expr_checked(rlen < UINT32_MAX);
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
			auto_free char *rbuf = malloc(rlen + 1);
			expr_checked(rbuf != NULL);
			expr_checked(read(fd, rbuf, rlen) == rlen);
			rbuf[rlen] = '\0';
			/* Unpack from JSON */
			JsonNode *root_node = json_decode(rbuf);
			if (root_node) {
				l_unpack_json(L, root_node);
			} else {
				lua_pushlstring(L, rbuf, rlen);
			}
			json_delete(root_node);
			lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
			continue;
		}
		/* Didn't respond */
		lua_pushboolean(L, false);
		lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
	}
	return 1;
}

#undef expr_checked


559
/** Trampoline function for module properties. */
560 561
static int l_trampoline(lua_State *L)
{
562 563
	struct kr_module *module = lua_touserdata(L, lua_upvalueindex(1));
	void* callback = lua_touserdata(L, lua_upvalueindex(2));
564
	struct engine *engine = engine_luaget(L);
565 566 567 568
	if (!module) {
		lua_pushstring(L, "module closure missing upvalue");
		lua_error(L);
	}
569

570 571 572
	/* Now we only have property callback or config,
	 * if we expand the callables, we might need a callback_type.
	 */
573
	const char *args = NULL;
574
	auto_free char *cleanup_args = NULL;
575
	if (lua_gettop(L) > 0) {
576
		if (lua_istable(L, 1) || lua_isboolean(L, 1)) {
577 578 579 580 581
			cleanup_args = l_pack_json(L, 1);
			args = cleanup_args;
		} else {
			args = lua_tostring(L, 1);
		}
582
	}
583
	if (callback == module->config) {
584
		module->config(module, args);
585 586
	} else {
		kr_prop_cb *prop = (kr_prop_cb *)callback;
587 588 589 590 591
		auto_free char *ret = prop(engine, module, args);
		if (!ret) { /* No results */
			return 0;
		}
		JsonNode *root_node = json_decode(ret);
592
		if (root_node) {
593 594 595 596 597
			l_unpack_json(L, root_node);
		} else {
			lua_pushstring(L, ret);
		}
		json_delete(root_node);
598
		return 1;
599
	}
600

601 602 603 604 605 606 607 608 609 610 611
	/* No results */
	return 0;
}

/*
 * Engine API.
 */

static int init_resolver(struct engine *engine)
{
	/* Open resolution context */
612 613
	engine->resolver.trust_anchors = map_make(NULL);
	engine->resolver.negative_anchors = map_make(NULL);
614
	engine->resolver.pool = engine->pool;
615
	engine->resolver.modules = &engine->modules;
616
	engine->resolver.cache_rtt_tout_retry_interval = KR_NS_TIMEOUT_RETRY_INTERVAL;
617 618 619 620 621 622
	/* Create OPT RR */
	engine->resolver.opt_rr = mm_alloc(engine->pool, sizeof(knot_rrset_t));
	if (!engine->resolver.opt_rr) {
		return kr_error(ENOMEM);
	}
	knot_edns_init(engine->resolver.opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, engine->pool);
623 624
	/* Use default TLS padding */
	engine->resolver.tls_padding = -1;
625
	/* Empty init; filled via ./lua/config.lua */
626
	kr_zonecut_init(&engine->resolver.root_hints, (const uint8_t *)"", engine->pool);
627
	/* Open NS rtt + reputation cache */
628 629 630
	lru_create(&engine->resolver.cache_rtt, LRU_RTT_SIZE, engine->pool, NULL);
	lru_create(&engine->resolver.cache_rep, LRU_REP_SIZE, engine->pool, NULL);
	lru_create(&engine->resolver.cache_cookie, LRU_COOKIES_SIZE, engine->pool, NULL);
631 632

	/* Load basic modules */
633 634
	engine_register(engine, "iterate", NULL, NULL);
	engine_register(engine, "validate", NULL, NULL);
635
	engine_register(engine, "cache", NULL, NULL);
636

637
	return array_push(engine->backends, kr_cdb_lmdb());
638 639 640 641 642 643 644 645 646 647
}

static int init_state(struct engine *engine)
{
	/* Initialize Lua state */
	engine->L = luaL_newstate();
	if (engine->L == NULL) {
		return kr_error(ENOMEM);
	}
	/* Initialize used libraries. */
648
	lua_gc(engine->L, LUA_GCSTOP, 0);
649 650 651 652 653 654
	luaL_openlibs(engine->L);
	/* Global functions */
	lua_pushcfunction(engine->L, l_help);
	lua_setglobal(engine->L, "help");
	lua_pushcfunction(engine->L, l_quit);
	lua_setglobal(engine->L, "quit");
655 656
	lua_pushcfunction(engine->L, l_hostname);
	lua_setglobal(engine->L, "hostname");
657 658
	lua_pushcfunction(engine->L, l_package_version);
	lua_setglobal(engine->L, "package_version");
659 660
	lua_pushcfunction(engine->L, l_moduledir);
	lua_setglobal(engine->L, "moduledir");
661 662
	lua_pushcfunction(engine->L, l_verbose);
	lua_setglobal(engine->L, "verbose");
663 664
	lua_pushcfunction(engine->L, l_setuser);
	lua_setglobal(engine->L, "user");
665 666
	lua_pushcfunction(engine->L, l_trustanchor);
	lua_setglobal(engine->L, "trustanchor");
667 668
	lua_pushcfunction(engine->L, l_hint_root_file);
	lua_setglobal(engine->L, "_hint_root_file");
669 670 671 672
	lua_pushliteral(engine->L, libknot_SONAME);
	lua_setglobal(engine->L, "libknot_SONAME");
	lua_pushliteral(engine->L, libzscanner_SONAME);
	lua_setglobal(engine->L, "libzscanner_SONAME");
673 674
	lua_pushcfunction(engine->L, l_tojson);
	lua_setglobal(engine->L, "tojson");
675 676
	lua_pushcfunction(engine->L, l_fromjson);
	lua_setglobal(engine->L, "fromjson");
677 678
	lua_pushcfunction(engine->L, l_map);
	lua_setglobal(engine->L, "map");
679 680 681 682 683
	lua_pushlightuserdata(engine->L, engine);
	lua_setglobal(engine->L, "__engine");
	return kr_ok();
}

684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
/**
 * Start luacov measurement and store results to file specified by
 * KRESD_COVERAGE_STATS environment variable.
 * Do nothing if the variable is not set.
 */
static void init_measurement(struct engine *engine)
{
	const char * const statspath = getenv("KRESD_COVERAGE_STATS");
	if (!statspath)
		return;

	char * snippet = NULL;
	int ret = asprintf(&snippet,
		"_luacov_runner = require('luacov.runner')\n"
		"_luacov_runner.init({\n"
		"	statsfile = '%s',\n"
		"	exclude = {'test', 'tapered', 'lua/5.1'},\n"
		"})\n"
		"jit.off()\n", statspath
	);
	assert(ret > 0);

	ret = luaL_loadstring(engine->L, snippet);
	assert(ret == 0);
	lua_call(engine->L, 0, 0);
	free(snippet);
}

712
int engine_init(struct engine *engine, knot_mm_t *pool)
713 714 715 716 717 718 719 720 721 722 723 724
{
	if (engine == NULL) {
		return kr_error(EINVAL);
	}

	memset(engine, 0, sizeof(*engine));
	engine->pool = pool;

	/* Initialize state */
	int ret = init_state(engine);
	if (ret != 0) {
		engine_deinit(engine);
725
		return ret;
726
	}
727
	init_measurement(engine);
728 729 730
	/* Initialize resolver */
	ret = init_resolver(engine);
	if (ret != 0) {
731
		engine_deinit(engine);
732 733
		return ret;
	}
734 735
	/* Initialize network */
	network_init(&engine->net, uv_default_loop());
736 737 738 739

	return ret;
}

740 741 742 743 744
static void engine_unload(struct engine *engine, struct kr_module *module)
{
	/* Unregister module */
	auto_free char *name = strdup(module->name);
	kr_module_unload(module);
745 746
	/* Clear in Lua world, but not for embedded modules ('cache' in particular). */
	if (name && !kr_module_embedded(name)) {
747 748 749 750 751 752
		lua_pushnil(engine->L);
		lua_setglobal(engine->L, name);
	}
	free(module);
}

753 754 755 756 757 758
void engine_deinit(struct engine *engine)
{
	if (engine == NULL) {
		return;
	}

759 760
	/* Only close sockets and services,
	 * no need to clean up mempool. */
761
	network_deinit(&engine->net);
762
	kr_zonecut_deinit(&engine->resolver.root_hints);
763
	kr_cache_close(&engine->resolver.cache);
764 765 766 767 768

	/* The lru keys are currently malloc-ated and need to be freed. */
	lru_free(engine->resolver.cache_rtt);
	lru_free(engine->resolver.cache_rep);
	lru_free(engine->resolver.cache_cookie);
769

770 771 772 773 774
	/* Clear IPC pipes */
	for (size_t i = 0; i < engine->ipc_set.len; ++i) {
		close(engine->ipc_set.at[i]);
	}

775
	/* Unload modules and engine. */
776
	for (size_t i = 0; i < engine->modules.len; ++i) {
777
		engine_unload(engine, engine->modules.at[i]);
778 779 780 781 782
	}
	if (engine->L) {
		lua_close(engine->L);
	}

783 784
	/* Free data structures */
	array_clear(engine->modules);
785
	array_clear(engine->backends);
786
	array_clear(engine->ipc_set);
787 788
	kr_ta_clear(&engine->resolver.trust_anchors);
	kr_ta_clear(&engine->resolver.negative_anchors);
789 790
	free(engine->hostname);
	free(engine->moduledir);
791 792
}

793
int engine_pcall(lua_State *L, int argc)
794 795 796
{
#if LUA_VERSION_NUM >= 502
	lua_getglobal(L, "_SANDBOX");
797
	lua_setupvalue(L, -(2 + argc), 1);
798
#endif
799
	return lua_pcall(L, argc, LUA_MULTRET, 0);
800 801
}

802
int engine_cmd(lua_State *L, const char *str, bool raw)
803
{
804
	if (L == NULL) {
805 806 807 808
		return kr_error(ENOEXEC);
	}

	/* Evaluate results */
809 810 811
	lua_getglobal(L, "eval_cmd");
	lua_pushstring(L, str);
	lua_pushboolean(L, raw);
812 813

	/* Check result. */
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
	return engine_pcall(L, 2);
}

int engine_ipc(struct engine *engine, const char *expr)
{
	if (engine == NULL || engine->L == NULL) {
		return kr_error(ENOEXEC);
	}

	/* Run expression and serialize response. */
	engine_cmd(engine->L, expr, true);
	if (lua_gettop(engine->L) > 0) {
		l_tojson(engine->L);
		return 1;
	} else {
		return 0;
	}
831 832
}

833
int engine_load_sandbox(struct engine *engine)
834
{
835
	/* Init environment */
836 837 838 839
	static const char sandbox_bytecode[] = {
		#include "daemon/lua/sandbox.inc"
	};
	if (l_dobytecode(engine->L, sandbox_bytecode, sizeof(sandbox_bytecode), "init") != 0) {
840 841
		fprintf(stderr, "[system] error %s\n", lua_tostring(engine->L, -1));
		lua_pop(engine->L, 1);
842 843
		return kr_error(ENOEXEC);
	}
844 845
	return kr_ok();
}
846

847 848 849 850
int engine_loadconf(struct engine *engine, const char *config_path)
{
	assert(config_path != NULL);
	int ret = l_dosandboxfile(engine->L, config_path);
851
	if (ret != 0) {
852
		fprintf(stderr, "%s\n", lua_tostring(engine->L, -1));
853 854
		lua_pop(engine->L, 1);
	}
855
	return ret;
856 857
}

858
int engine_load_defaults(struct engine *engine)
859
{
860 861 862 863 864
	/* Load defaults */
	static const char config_bytecode[] = {
		#include "daemon/lua/config.inc"
	};
	int ret = l_dobytecode(engine->L, config_bytecode, sizeof(config_bytecode), "config");
865
	if (ret != 0) {
866 867
		fprintf(stderr, "%s\n", lua_tostring(engine->L, -1));
		lua_pop(engine->L, 1);
868
	}
869 870
	return ret;
}
871

872 873
int engine_start(struct engine *engine)
{
874 875 876
	/* Clean up stack and restart GC */
	lua_settop(engine->L, 0);
	lua_gc(engine->L, LUA_GCCOLLECT, 0);
877
	lua_gc(engine->L, LUA_GCSETSTEPMUL, 50);
878 879
	lua_gc(engine->L, LUA_GCSETPAUSE, 400);
	lua_gc(engine->L, LUA_GCRESTART, 0);
880

881
	return kr_ok();
882 883 884 885
}

void engine_stop(struct engine *engine)
{
886 887 888
	if (!engine) {
		return;
	}
889 890 891
	uv_stop(uv_default_loop());
}

892
/** Register module properties in Lua environment, if any. */
893 894
static int register_properties(struct engine *engine, struct kr_module *module)
{
895 896 897
	if (!module->config && !module->props) {
		return kr_ok();
	}
898 899 900 901
	lua_newtable(engine->L);
	if (module->config != NULL) {
		REGISTER_MODULE_CALL(engine->L, module, module->config, "config");
	}
902 903 904 905

	const struct kr_prop *p = module->props == NULL ? NULL : module->props();
	for (; p && p->name; ++p) {
		if (p->cb != NULL) {
906 907 908 909 910 911 912 913
			REGISTER_MODULE_CALL(engine->L, module, p->cb, p->name);
		}
	}
	lua_setglobal(engine->L, module->name);

	/* Register module in Lua env */
	lua_getglobal(engine->L, "modules_register");
	lua_getglobal(engine->L, module->name);
914
	if (engine_pcall(engine->L, 1) != 0) {
915 916 917 918 919 920
		lua_pop(engine->L, 1);
	}

	return kr_ok();
}

921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
/** @internal Find matching module */
static size_t module_find(module_array_t *mod_list, const char *name)
{
	size_t found = mod_list->len;
	for (size_t i = 0; i < mod_list->len; ++i) {
		struct kr_module *mod = mod_list->at[i];
		if (strcmp(mod->name, name) == 0) {
			found = i;
			break;
		}
	}
	return found;
}

int engine_register(struct engine *engine, const char *name, const char *precedence, const char* ref)
936 937 938 939
{
	if (engine == NULL || name == NULL) {
		return kr_error(EINVAL);
	}
940 941
	/* Make sure module is unloaded */
	(void) engine_unregister(engine, name);
942 943 944 945 946 947 948 949 950
	/* Find the index of referenced module. */
	module_array_t *mod_list = &engine->modules;
	size_t ref_pos = mod_list->len;
	if (precedence && ref) {
		ref_pos = module_find(mod_list, ref);
		if (ref_pos >= mod_list->len) {
			return kr_error(EIDRM);
		}
	}
951
	/* Attempt to load binary module */
952 953 954 955
	struct kr_module *module = malloc(sizeof(*module));
	if (!module) {
		return kr_error(ENOMEM);
	}
956
	module->data = engine;
957
	int ret = kr_module_load(module, name, engine->moduledir);
958 959
	/* Load Lua module if not a binary */
	if (ret == kr_error(ENOENT)) {
960
		ret = ffimodule_register_lua(engine, module, name);
961 962 963
	} else if (ret == kr_error(ENOTSUP)) {
		/* Print a more helpful message when module is linked against an old resolver ABI. */
		fprintf(stderr, "[system] module '%s' links to unsupported ABI, please rebuild it\n", name);
964
	}
965
	if (ret != 0) {
966
		free(module);
967
		return ret;
968 969 970 971
	}
	if (array_push(engine->modules, module) < 0) {
		engine_unload(engine, module);
		return kr_error(ENOMEM);
972
	}
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988
	/* Evaluate precedence operator */
	if (precedence) {
		struct kr_module **arr = mod_list->at;
		size_t emplacement = mod_list->len;
		if (strcasecmp(precedence, ">") == 0) {
			if (ref_pos + 1 < mod_list->len)
				emplacement = ref_pos + 1; /* Insert after target */
		}
		if (strcasecmp(precedence, "<") == 0) {
			emplacement = ref_pos; /* Insert at target */
		}
		/* Move the tail if it has some elements. */
		if (emplacement + 1 < mod_list->len) {
			memmove(&arr[emplacement + 1], &arr[emplacement], sizeof(*arr) * (mod_list->len - (emplacement + 1)));
			arr[emplacement] = module;
		}
989
	}
990

991
	return register_properties(engine, module);
992 993 994 995
}

int engine_unregister(struct engine *engine, const char *name)
{
996
	module_array_t *mod_list = &engine->modules;
997
	size_t found = module_find(mod_list, name);
998
	if (found < mod_list->len) {
999
		engine_unload(engine, mod_list->at[found]);
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
		array_del(*mod_list, found);
		return kr_ok();
	}

	return kr_error(ENOENT);
}

void engine_lualib(struct engine *engine, const char *name, lua_CFunction lib_cb)
{
	if (engine != NULL) {
1010
#if LUA_VERSION_NUM >= 502
1011 1012
		luaL_requiref(engine->L, name, lib_cb, 1);
		lua_pop(engine->L, 1);
1013 1014
#else
		lib_cb(engine->L);
1015 1016 1017 1018 1019 1020
#endif
	}
}

struct engine *engine_luaget(lua_State *L)
{
1021
	lua_getglobal(L, "__engine");
1022
	struct engine *engine = lua_touserdata(L, -1);
1023
	if (!engine) luaL_error(L, "internal error, empty engine pointer");
1024
	lua_pop(L, 1);
1025
	return engine;
1026
}