1 /* ==========================================================================
2  * dns.c - Lua Continuation Queues
3  * --------------------------------------------------------------------------
4  * Copyright (c) 2012, 2014  William Ahern
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to permit
11  * persons to whom the Software is furnished to do so, subject to the
12  * following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20  * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23  * USE OR OTHER DEALINGS IN THE SOFTWARE.
24  * ==========================================================================
25  */
26 #include "config.h"
27 
28 #include <limits.h> /* UINT_MAX */
29 #include <stddef.h> /* offsetof */
30 #include <stdlib.h> /* free(3) */
31 #include <stdio.h>  /* tmpfile(3) fclose(3) */
32 #include <string.h> /* memset(3) strcmp(3) */
33 #include <errno.h>
34 
35 #include <sys/types.h>
36 #include <sys/socket.h> /* AF_INET AF_INET6 */
37 #include <netinet/in.h> /* struct sockaddr_in struct sockaddr_in6 */
38 #include <arpa/inet.h>  /* INET_ADDSTRLEN INET6_ADDRSTRLEN inet_ntop(3) */
39 
40 #include <lua.h>
41 #include <lauxlib.h>
42 
43 #include "lib/dns.h"
44 #include "cqueues.h"
45 
46 #define RR_ANY_CLASS   "DNS RR Any"
47 #define RR_A_CLASS     "DNS RR A"
48 #define RR_NS_CLASS    "DNS RR NS"
49 #define RR_CNAME_CLASS "DNS RR CNAME"
50 #define RR_SOA_CLASS   "DNS RR SOA"
51 #define RR_PTR_CLASS   "DNS RR PTR"
52 #define RR_MX_CLASS    "DNS RR MX"
53 #define RR_TXT_CLASS   "DNS RR TXT"
54 #define RR_AAAA_CLASS  "DNS RR AAAA"
55 #define RR_SRV_CLASS   "DNS RR SRV"
56 #define RR_OPT_CLASS   "DNS RR OPT"
57 #define RR_SSHFP_CLASS "DNS RR SSHFP"
58 #define RR_SPF_CLASS   "DNS RR SPF"
59 
60 #define PACKET_CLASS   "DNS Packet"
61 #define RESCONF_CLASS  "DNS Config"
62 #define HOSTS_CLASS    "DNS Hosts"
63 #define HINTS_CLASS    "DNS Hints"
64 #define RESOLVER_CLASS "DNS Resolver"
65 
66 
optfint(lua_State * L,int t,const char * k,int def)67 static int optfint(lua_State *L, int t, const char *k, int def) {
68 	int i;
69 
70 	lua_getfield(L, t, k);
71 	i = luaL_optint(L, -1, def);
72 	lua_pop(L, 1);
73 
74 	return i;
75 } /* optfint() */
76 
77 
optfbool(lua_State * L,int t,const char * k,_Bool def)78 static int optfbool(lua_State *L, int t, const char *k, _Bool def) {
79 	_Bool b;
80 
81 	lua_getfield(L, t, k);
82 	b = (lua_isnil(L, -1))? def : lua_toboolean(L, -1);
83 	lua_pop(L, 1);
84 
85 	return b;
86 } /* optfbool() */
87 
88 
89 /*
90  * R E S O U R C E  R E C O R D  B I N D I N G S
91  *
92  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
93 
94 struct rr {
95 	struct dns_rr attr;
96 	char *name;
97 	union dns_any data;
98 }; /* struct rr */
99 
100 
101 static const struct rr_info {
102 	const char *tname;
103 	unsigned short bufsiz;
104 } rrinfo[] = {
105 	[DNS_T_A]     = { RR_A_CLASS,     sizeof (struct dns_a) },
106 	[DNS_T_NS]    = { RR_NS_CLASS,    sizeof (struct dns_ns) },
107 	[DNS_T_CNAME] = { RR_CNAME_CLASS, sizeof (struct dns_cname) },
108 	[DNS_T_SOA]   = { RR_SOA_CLASS,   sizeof (struct dns_soa) },
109 	[DNS_T_PTR]   = { RR_PTR_CLASS,   sizeof (struct dns_ptr) },
110 	[DNS_T_MX]    = { RR_MX_CLASS,    sizeof (struct dns_mx) },
111 	[DNS_T_TXT]   = { RR_TXT_CLASS,   0 },
112 	[DNS_T_AAAA]  = { RR_AAAA_CLASS,  sizeof (struct dns_aaaa) },
113 	[DNS_T_SRV]   = { RR_SRV_CLASS,   sizeof (struct dns_srv) },
114 	[DNS_T_OPT]   = { RR_OPT_CLASS,   sizeof (struct dns_opt) },
115 	[DNS_T_SSHFP] = { RR_SSHFP_CLASS, sizeof (struct dns_sshfp) },
116 	[DNS_T_SPF]   = { RR_SPF_CLASS,   0 },
117 };
118 
rr_info(int type)119 static const struct rr_info *rr_info(int type) {
120 	return (type >= 0 && type < (int)countof(rrinfo))? &rrinfo[type] : 0;
121 } /* rr_info() */
122 
rr_tname(const struct dns_rr * rr)123 static const char *rr_tname(const struct dns_rr *rr) {
124 	const struct rr_info *info;
125 
126 	if ((info = rr_info(rr->type)) && info->tname)
127 		return info->tname;
128 	else
129 		return RR_ANY_CLASS;
130 } /* rr_tname() */
131 
rr_bufsiz(const struct dns_rr * rr)132 static size_t rr_bufsiz(const struct dns_rr *rr) {
133 	const struct rr_info *info;
134 	size_t minbufsiz = offsetof(struct dns_txt, data) + rr->rd.len + 1;
135 
136 	if ((info = rr_info(rr->type)) && info->bufsiz)
137 		return MAX(info->bufsiz, minbufsiz);
138 	else
139 		return minbufsiz;
140 } /* rr_bufsiz() */
141 
rr_push(lua_State * L,struct dns_rr * any,struct dns_packet * P)142 static void rr_push(lua_State *L, struct dns_rr *any, struct dns_packet *P) {
143 	char name[DNS_D_MAXNAME + 1];
144 	size_t namelen, datasiz;
145 	struct rr *rr;
146 	int error;
147 
148 	namelen = dns_d_expand(name, sizeof name, any->dn.p, P, &error);
149 	datasiz = rr_bufsiz(any);
150 
151 	rr = lua_newuserdata(L, offsetof(struct rr, data) + datasiz + namelen + 1);
152 
153 	rr->attr = *any;
154 
155 	rr->name = (char *)rr + offsetof(struct rr, data) + datasiz;
156 	memcpy(rr->name, name, namelen);
157 	rr->name[namelen] = '\0';
158 
159 	memset(&rr->data, '\0', datasiz);
160 
161 	if (any->section != DNS_S_QD) {
162 		dns_any_init(&rr->data, datasiz);
163 
164 		if ((error = dns_any_parse(&rr->data, any, P)))
165 			luaL_error(L, "dns.rr.parse: %s", cqs_strerror(error));
166 	}
167 
168 	luaL_setmetatable(L, rr_tname(any));
169 } /* rr_push() */
170 
171 
rr_toany(lua_State * L,int index)172 static struct rr *rr_toany(lua_State *L, int index) {
173 	luaL_checktype(L, index, LUA_TUSERDATA);
174 	luaL_argcheck(L, lua_rawlen(L, index) > offsetof(struct rr, data) + 4, index, "DNS RR userdata too small");
175 
176 	return lua_touserdata(L, index);
177 } /* rr_toany() */
178 
179 
180 /*
181  * ANY RR Bindings
182  */
any_section(lua_State * L)183 static int any_section(lua_State *L) {
184 	struct rr *rr = rr_toany(L, 1);
185 
186 	lua_pushinteger(L, rr->attr.section);
187 
188 	return 1;
189 } /* any_section() */
190 
any_name(lua_State * L)191 static int any_name(lua_State *L) {
192 	struct rr *rr = rr_toany(L, 1);
193 
194 	lua_pushstring(L, rr->name);
195 
196 	return 1;
197 } /* any_name() */
198 
any_type(lua_State * L)199 static int any_type(lua_State *L) {
200 	struct rr *rr = rr_toany(L, 1);
201 
202 	lua_pushinteger(L, rr->attr.type);
203 
204 	return 1;
205 } /* any_type() */
206 
any_class(lua_State * L)207 static int any_class(lua_State *L) {
208 	struct rr *rr = rr_toany(L, 1);
209 
210 	lua_pushinteger(L, rr->attr.class);
211 
212 	return 1;
213 } /* any_class() */
214 
any_ttl(lua_State * L)215 static int any_ttl(lua_State *L) {
216 	struct rr *rr = rr_toany(L, 1);
217 
218 	lua_pushinteger(L, rr->attr.ttl);
219 
220 	return 1;
221 } /* any_ttl() */
222 
any_rdata(lua_State * L)223 static int any_rdata(lua_State *L) {
224 	struct rr *rr = rr_toany(L, 1);
225 
226 	if (rr->attr.section == DNS_S_QD)
227 		return lua_pushliteral(L, ""), 1;
228 
229 	lua_pushlstring(L, (char *)rr->data.rdata.data, rr->data.rdata.len);
230 
231 	return 1;
232 } /* any_rdata() */
233 
any__tostring(lua_State * L)234 static int any__tostring(lua_State *L) {
235 	struct rr *rr = rr_toany(L, 1);
236 
237 	if (rr->attr.section == DNS_S_QD)
238 		return lua_pushliteral(L, ""), 1;
239 
240 	if (luaL_testudata(L, 1, RR_ANY_CLASS)) {
241 		lua_pushlstring(L, (char *)rr->data.rdata.data, rr->data.rdata.len);
242 	} else {
243 		luaL_Buffer B;
244 		size_t len;
245 
246 		luaL_buffinit(L, &B);
247 		len = dns_any_print(luaL_prepbuffer(&B), LUAL_BUFFERSIZE, &rr->data, rr->attr.type);
248 		luaL_addsize(&B, len);
249 		luaL_pushresult(&B);
250 	}
251 
252 	return 1;
253 } /* any__tostring() */
254 
255 static const luaL_Reg any_methods[] = {
256 	{ "section", &any_section },
257 	{ "name",    &any_name },
258 	{ "type",    &any_type },
259 	{ "class",   &any_class },
260 	{ "ttl",     &any_ttl },
261 	{ "rdata",   &any_rdata },
262 	{ NULL,      NULL }
263 }; /* any_methods[] */
264 
265 static const luaL_Reg any_metatable[] = {
266 	{ "__tostring", &any__tostring },
267 	{ NULL,         NULL }
268 }; /* any_metatable[] */
269 
270 
271 /*
272  * A RR Bindings
273  */
a_addr(lua_State * L)274 static int a_addr(lua_State *L) {
275 	struct rr *rr = luaL_checkudata(L, 1, RR_A_CLASS);
276 	char addr[INET_ADDRSTRLEN + 1] = "";
277 
278 	if (rr->attr.section != DNS_S_QD)
279 		inet_ntop(AF_INET, &rr->data.a.addr, addr, sizeof addr);
280 	lua_pushstring(L, addr);
281 
282 	return 1;
283 } /* a_addr() */
284 
285 static const luaL_Reg a_methods[] = {
286 	{ "section", &any_section },
287 	{ "name",    &any_name },
288 	{ "type",    &any_type },
289 	{ "class",   &any_class },
290 	{ "ttl",     &any_ttl },
291 	{ "addr",    &a_addr },
292 	{ NULL,      NULL }
293 }; /* a_methods[] */
294 
295 static const luaL_Reg a_metatable[] = {
296 	{ "__tostring", &a_addr },
297 	{ NULL,         NULL }
298 }; /* a_metatable[] */
299 
300 
301 /*
302  * NS, CNAME, PTR RR Bindings
303  */
ns_host(lua_State * L)304 static int ns_host(lua_State *L) {
305 	struct rr *rr = rr_toany(L, 1);
306 
307 	if (rr->attr.section == DNS_S_QD)
308 		return lua_pushliteral(L, ""), 1;
309 
310 	lua_pushstring(L, rr->data.ns.host);
311 
312 	return 1;
313 } /* ns_host() */
314 
315 static const luaL_Reg ns_methods[] = {
316 	{ "section", &any_section },
317 	{ "name",    &any_name },
318 	{ "type",    &any_type },
319 	{ "class",   &any_class },
320 	{ "ttl",     &any_ttl },
321 	{ "host",    &ns_host },
322 	{ NULL,      NULL }
323 }; /* ns_methods[] */
324 
325 static const luaL_Reg ns_metatable[] = {
326 	{ "__tostring", &ns_host },
327 	{ NULL,         NULL }
328 }; /* ns_metatable[] */
329 
330 
331 /*
332  * SOA RR Bindings
333  */
soa_mname(lua_State * L)334 static int soa_mname(lua_State *L) {
335 	struct rr *rr = luaL_checkudata(L, 1, RR_SOA_CLASS);
336 
337 	lua_pushstring(L, rr->data.soa.mname);
338 
339 	return 1;
340 } /* soa_mname() */
341 
soa_rname(lua_State * L)342 static int soa_rname(lua_State *L) {
343 	struct rr *rr = luaL_checkudata(L, 1, RR_SOA_CLASS);
344 
345 	lua_pushstring(L, rr->data.soa.rname);
346 
347 	return 1;
348 } /* soa_rname() */
349 
soa_serial(lua_State * L)350 static int soa_serial(lua_State *L) {
351 	struct rr *rr = luaL_checkudata(L, 1, RR_SOA_CLASS);
352 
353 	lua_pushinteger(L, rr->data.soa.serial);
354 
355 	return 1;
356 } /* soa_serial() */
357 
soa_refresh(lua_State * L)358 static int soa_refresh(lua_State *L) {
359 	struct rr *rr = luaL_checkudata(L, 1, RR_SOA_CLASS);
360 
361 	lua_pushinteger(L, rr->data.soa.refresh);
362 
363 	return 1;
364 } /* soa_refresh() */
365 
soa_retry(lua_State * L)366 static int soa_retry(lua_State *L) {
367 	struct rr *rr = luaL_checkudata(L, 1, RR_SOA_CLASS);
368 
369 	lua_pushinteger(L, rr->data.soa.retry);
370 
371 	return 1;
372 } /* soa_retry() */
373 
soa_expire(lua_State * L)374 static int soa_expire(lua_State *L) {
375 	struct rr *rr = luaL_checkudata(L, 1, RR_SOA_CLASS);
376 
377 	lua_pushinteger(L, rr->data.soa.expire);
378 
379 	return 1;
380 } /* soa_expire() */
381 
soa_minimum(lua_State * L)382 static int soa_minimum(lua_State *L) {
383 	struct rr *rr = luaL_checkudata(L, 1, RR_SOA_CLASS);
384 
385 	lua_pushinteger(L, rr->data.soa.minimum);
386 
387 	return 1;
388 } /* soa_minimum() */
389 
390 static const luaL_Reg soa_methods[] = {
391 	{ "section", &any_section },
392 	{ "name",    &any_name },
393 	{ "type",    &any_type },
394 	{ "class",   &any_class },
395 	{ "ttl",     &any_ttl },
396 	{ "mname",   &soa_mname },
397 	{ "rname",   &soa_rname },
398 	{ "serial",  &soa_serial },
399 	{ "refresh", &soa_refresh },
400 	{ "retry",   &soa_retry },
401 	{ "expire",  &soa_expire },
402 	{ "minimum", &soa_minimum },
403 	{ NULL,    NULL }
404 }; /* soa_methods[] */
405 
406 static const luaL_Reg soa_metatable[] = {
407 	{ "__tostring", &any__tostring },
408 	{ NULL,         NULL }
409 }; /* soa_metatable[] */
410 
411 
412 /*
413  * MX RR Bindings
414  */
mx_host(lua_State * L)415 static int mx_host(lua_State *L) {
416 	struct rr *rr = luaL_checkudata(L, 1, RR_MX_CLASS);
417 
418 	lua_pushstring(L, rr->data.mx.host);
419 
420 	return 1;
421 } /* mx_host() */
422 
mx_preference(lua_State * L)423 static int mx_preference(lua_State *L) {
424 	struct rr *rr = luaL_checkudata(L, 1, RR_MX_CLASS);
425 
426 	lua_pushinteger(L, rr->data.mx.preference);
427 
428 	return 1;
429 } /* mx_preference() */
430 
431 static const luaL_Reg mx_methods[] = {
432 	{ "section",    &any_section },
433 	{ "name",       &any_name },
434 	{ "type",       &any_type },
435 	{ "class",      &any_class },
436 	{ "ttl",        &any_ttl },
437 	{ "host",       &mx_host },
438 	{ "preference", &mx_preference },
439 	{ NULL,         NULL }
440 }; /* mx_methods[] */
441 
442 static const luaL_Reg mx_metatable[] = {
443 	{ "__tostring", &any__tostring },
444 	{ NULL,         NULL }
445 }; /* mx_metatable[] */
446 
447 
448 /*
449  * TXT RR Bindings
450  */
451 static const luaL_Reg txt_methods[] = {
452 	{ "section", &any_section },
453 	{ "name",    &any_name },
454 	{ "type",    &any_type },
455 	{ "class",   &any_class },
456 	{ "ttl",     &any_ttl },
457 	{ "data",    &any_rdata },
458 	{ NULL,      NULL }
459 }; /* txt_methods[] */
460 
461 static const luaL_Reg txt_metatable[] = {
462 	{ "__tostring", &any__tostring },
463 	{ NULL,         NULL }
464 }; /* txt_metatable[] */
465 
466 
467 /*
468  * AAAA RR Bindings
469  */
aaaa_addr(lua_State * L)470 static int aaaa_addr(lua_State *L) {
471 	struct rr *rr = luaL_checkudata(L, 1, RR_AAAA_CLASS);
472 	char addr[INET6_ADDRSTRLEN + 1] = "";
473 
474 	if (rr->attr.section != DNS_S_QD)
475 		inet_ntop(AF_INET6, &rr->data.aaaa.addr, addr, sizeof addr);
476 	lua_pushstring(L, addr);
477 
478 	return 1;
479 } /* aaaa_addr() */
480 
481 static const luaL_Reg aaaa_methods[] = {
482 	{ "section", &any_section },
483 	{ "name",    &any_name },
484 	{ "type",    &any_type },
485 	{ "class",   &any_class },
486 	{ "ttl",     &any_ttl },
487 	{ "addr",    &aaaa_addr },
488 	{ NULL,      NULL }
489 }; /* aaaa_methods[] */
490 
491 static const luaL_Reg aaaa_metatable[] = {
492 	{ "__tostring", &aaaa_addr },
493 	{ NULL,         NULL }
494 }; /* aaaa_metatable[] */
495 
496 
497 /*
498  * SRV RR Bindings
499  */
srv_priority(lua_State * L)500 static int srv_priority(lua_State *L) {
501 	struct rr *rr = luaL_checkudata(L, 1, RR_SRV_CLASS);
502 
503 	lua_pushinteger(L, rr->data.srv.priority);
504 
505 	return 1;
506 } /* srv_priority() */
507 
srv_weight(lua_State * L)508 static int srv_weight(lua_State *L) {
509 	struct rr *rr = luaL_checkudata(L, 1, RR_SRV_CLASS);
510 
511 	lua_pushinteger(L, rr->data.srv.weight);
512 
513 	return 1;
514 } /* srv_weight() */
515 
srv_port(lua_State * L)516 static int srv_port(lua_State *L) {
517 	struct rr *rr = luaL_checkudata(L, 1, RR_SRV_CLASS);
518 
519 	lua_pushinteger(L, rr->data.srv.port);
520 
521 	return 1;
522 } /* srv_port() */
523 
srv_target(lua_State * L)524 static int srv_target(lua_State *L) {
525 	struct rr *rr = luaL_checkudata(L, 1, RR_SRV_CLASS);
526 
527 	lua_pushstring(L, rr->data.srv.target);
528 
529 	return 1;
530 } /* srv_target() */
531 
532 static const luaL_Reg srv_methods[] = {
533 	{ "section",  &any_section },
534 	{ "name",     &any_name },
535 	{ "type",     &any_type },
536 	{ "class",    &any_class },
537 	{ "ttl",      &any_ttl },
538 	{ "priority", &srv_priority },
539 	{ "weight",   &srv_weight },
540 	{ "port",     &srv_port },
541 	{ "target",   &srv_target },
542 	{ NULL,       NULL }
543 }; /* srv_methods[] */
544 
545 static const luaL_Reg srv_metatable[] = {
546 	{ "__tostring", &any__tostring },
547 	{ NULL,         NULL }
548 }; /* srv_metatable[] */
549 
550 
551 /*
552  * OPT RR Bindings
553  */
opt_rcode(lua_State * L)554 static int opt_rcode(lua_State *L) {
555 	struct rr *rr = luaL_checkudata(L, 1, RR_OPT_CLASS);
556 
557 	lua_pushinteger(L, rr->data.opt.rcode);
558 
559 	return 1;
560 } /* opt_rcode() */
561 
opt_version(lua_State * L)562 static int opt_version(lua_State *L) {
563 	struct rr *rr = luaL_checkudata(L, 1, RR_OPT_CLASS);
564 
565 	lua_pushinteger(L, rr->data.opt.version);
566 
567 	return 1;
568 } /* opt_version() */
569 
opt_maxsize(lua_State * L)570 static int opt_maxsize(lua_State *L) {
571 	struct rr *rr = luaL_checkudata(L, 1, RR_OPT_CLASS);
572 
573 	lua_pushinteger(L, rr->data.opt.maxsize);
574 
575 	return 1;
576 } /* opt_maxsize() */
577 
578 static const luaL_Reg opt_methods[] = {
579 	{ "section", &any_section },
580 	{ "name",    &any_name },
581 	{ "type",    &any_type },
582 	{ "class",   &any_class },
583 	{ "ttl",     &any_ttl },
584 	{ "rcode",   &opt_rcode },
585 	{ "version", &opt_version },
586 	{ "maxsize", &opt_maxsize },
587 	{ NULL,      NULL }
588 }; /* opt_methods[] */
589 
590 static const luaL_Reg opt_metatable[] = {
591 	{ "__tostring", &any__tostring },
592 	{ NULL,         NULL }
593 }; /* opt_metatable[] */
594 
595 
596 /*
597  * SSHFP RR Bindings
598  */
sshfp_algo(lua_State * L)599 static int sshfp_algo(lua_State *L) {
600 	struct rr *rr = luaL_checkudata(L, 1, RR_SSHFP_CLASS);
601 
602 	lua_pushinteger(L, rr->data.sshfp.algo);
603 
604 	return 1;
605 } /* sshfp_algo() */
606 
607 
sshfp_digest(lua_State * L)608 static int sshfp_digest(lua_State *L) {
609 	struct rr *rr = luaL_checkudata(L, 1, RR_SSHFP_CLASS);
610 	int fmt = luaL_checkoption(L, 2, "x", (const char *[]){ "s", "x", 0 });
611 	unsigned char *hash;
612 	size_t hashlen;
613 
614 	lua_pushinteger(L, rr->data.sshfp.type);
615 
616 	switch (rr->data.sshfp.type) {
617 	case DNS_SSHFP_SHA1:
618 		hash = rr->data.sshfp.digest.sha1;
619 		hashlen = sizeof rr->data.sshfp.digest.sha1;
620 
621 		break;
622 	default:
623 		lua_pushnil(L);
624 
625 		return 2;
626 	}
627 
628 	switch (fmt) {
629 	case 1: {
630 		luaL_Buffer B;
631 		size_t i;
632 
633 		luaL_buffinit(L, &B);
634 
635 		for (i = 0; i < hashlen; i++) {
636 			luaL_addchar(&B, "0123456789abcdef"[0x0f & (hash[i] >> 4)]);
637 			luaL_addchar(&B, "0123456789abcdef"[0x0f & (hash[i] >> 0)]);
638 		}
639 
640 		luaL_pushresult(&B);
641 
642 		break;
643 	}
644 	default:
645 		lua_pushlstring(L, (char *)hash, hashlen);
646 		break;
647 	} /* switch() */
648 
649 	return 2;
650 } /* sshfp_digest() */
651 
652 
653 static const luaL_Reg sshfp_methods[] = {
654 	{ "section", &any_section },
655 	{ "name",    &any_name },
656 	{ "type",    &any_type },
657 	{ "class",   &any_class },
658 	{ "ttl",     &any_ttl },
659 	{ "algo",    &sshfp_algo },
660 	{ "digest",  &sshfp_digest },
661 	{ NULL,     NULL }
662 }; /* sshfp_methods[] */
663 
664 static const luaL_Reg sshfp_metatable[] = {
665 	{ "__tostring", &any__tostring },
666 	{ NULL,         NULL }
667 }; /* sshfp_metatable[] */
668 
669 
670 /*
671  * SPF RR Bindings
672  */
673 static const luaL_Reg spf_methods[] = {
674 	{ "section", &any_section },
675 	{ "name",    &any_name },
676 	{ "type",    &any_type },
677 	{ "class",   &any_class },
678 	{ "ttl",     &any_ttl },
679 	{ "policy",  &any_rdata },
680 	{ "data",    &any_rdata },
681 	{ NULL,      NULL }
682 }; /* spf_methods[] */
683 
684 static const luaL_Reg spf_metatable[] = {
685 	{ "__tostring", &any_rdata },
686 	{ NULL,         NULL }
687 }; /* spf_metatable[] */
688 
689 
rr_loadall(lua_State * L)690 static void rr_loadall(lua_State *L) {
691 	int top = lua_gettop(L);
692 
693 	cqs_newmetatable(L, RR_ANY_CLASS, any_methods, any_metatable, 0);
694 	cqs_newmetatable(L, RR_A_CLASS, a_methods, a_metatable, 0);
695 	cqs_newmetatable(L, RR_NS_CLASS, ns_methods, ns_metatable, 0);
696 	cqs_newmetatable(L, RR_CNAME_CLASS, ns_methods, ns_metatable, 0);
697 	cqs_newmetatable(L, RR_SOA_CLASS, soa_methods, soa_metatable, 0);
698 	cqs_newmetatable(L, RR_PTR_CLASS, ns_methods, ns_metatable, 0);
699 	cqs_newmetatable(L, RR_MX_CLASS, mx_methods, mx_metatable, 0);
700 	cqs_newmetatable(L, RR_TXT_CLASS, txt_methods, txt_metatable, 0);
701 	cqs_newmetatable(L, RR_AAAA_CLASS, aaaa_methods, aaaa_metatable, 0);
702 	cqs_newmetatable(L, RR_SRV_CLASS, srv_methods, srv_metatable, 0);
703 	cqs_newmetatable(L, RR_OPT_CLASS, opt_methods, opt_metatable, 0);
704 	cqs_newmetatable(L, RR_SSHFP_CLASS, sshfp_methods, sshfp_metatable, 0);
705 	cqs_newmetatable(L, RR_SPF_CLASS, spf_methods, spf_metatable, 0);
706 
707 	lua_settop(L, top);
708 } /* rr_loadall() */
709 
710 
rr_type(lua_State * L)711 static int rr_type(lua_State *L) {
712 	unsigned i;
713 
714 	lua_settop(L, 2);
715 	lua_pushnil(L); /* default result */
716 
717 	if (lua_isuserdata(L, 2)) {
718 		for (i = 0; i < countof(rrinfo); i++) {
719 			if (!rrinfo[i].tname)
720 				continue;
721 			if (!luaL_testudata(L, 2, rrinfo[i].tname)
722 			&&  !luaL_testudata(L, 2, RR_ANY_CLASS))
723 				continue;
724 
725 			lua_pushstring(L, "dns record");
726 
727 			break;
728 		}
729 	}
730 
731 	return 1;
732 } /* rr_type() */
733 
734 
735 static const luaL_Reg rr_globals[] = {
736 	{ NULL, NULL }
737 };
738 
739 
luaopen__cqueues_dns_record(lua_State * L)740 int luaopen__cqueues_dns_record(lua_State *L) {
741 	static const struct cqs_macro classes[] = {
742 		{ "IN", DNS_C_IN }, { "ANY", DNS_C_ANY },
743 	};
744 	static const struct cqs_macro types[] = {
745 		{ "A",     DNS_T_A },     { "NS",   DNS_T_NS },
746 		{ "CNAME", DNS_T_CNAME }, { "SOA",  DNS_T_SOA },
747 		{ "PTR",   DNS_T_PTR },   { "MX",   DNS_T_MX },
748 		{ "TXT",   DNS_T_TXT },   { "AAAA", DNS_T_AAAA },
749 		{ "SRV",   DNS_T_SRV },   { "OPT",  DNS_T_OPT },
750 		{ "SSHFP", DNS_T_SSHFP }, { "SPF",  DNS_T_SPF },
751 		{ "ALL",   DNS_T_ALL },
752 	};
753 	static const struct cqs_macro sshfp[] = {
754 		{ "RSA",  DNS_SSHFP_RSA }, { "DSA", DNS_SSHFP_DSA },
755 		{ "SHA1", DNS_SSHFP_SHA1 },
756 	};
757 
758 	rr_loadall(L);
759 
760 	luaL_newlib(L, rr_globals);
761 
762 	lua_createtable(L, 0, countof(classes));
763 	cqs_setmacros(L, -1, classes, countof(classes), 1);
764 	lua_setfield(L, -2, "class");
765 
766 	lua_createtable(L, 0, countof(types));
767 	cqs_setmacros(L, -1, types, countof(types), 1);
768 	lua_createtable(L, 0, 1);
769 	lua_pushcfunction(L, &rr_type);
770 	lua_setfield(L, -2, "__call");
771 	lua_setmetatable(L, -2);
772 	lua_setfield(L, -2, "type");
773 
774 	lua_createtable(L, 0, countof(sshfp));
775 	cqs_setmacros(L, -1, sshfp, countof(sshfp), 1);
776 	lua_setfield(L, -2, "sshfp");
777 
778 	return 1;
779 } /* luaopen__cqueues_dns_record() */
780 
781 
782 /*
783  * P A C K E T  B I N D I N G S
784  *
785  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
786 
pkt_reload(struct dns_packet * P,const void * data,size_t size)787 static void pkt_reload(struct dns_packet *P, const void *data, size_t size) {
788 	if (P->size < size) {
789 		memcpy(P->data, data, P->size);
790 		P->end = P->size;
791 		dns_header(P)->tc = 1;
792 	} else {
793 		memcpy(P->data, data, size);
794 		P->end = size;
795 	}
796 
797 	dns_p_study(P);
798 
799 	memset(P->dict, 0, sizeof P->dict);
800 	dns_p_dictadd(P, 12); /* add query name to dictionary */
801 } /* pkt_reload() */
802 
803 
pkt_new(lua_State * L)804 static int pkt_new(lua_State *L) {
805 	struct dns_packet *P;
806 	const char *data = NULL;
807 	size_t prepbufsiz, datasiz, size;
808 
809 	if (lua_isnoneornil(L, 1) || lua_isnumber(L, 1)) {
810 		prepbufsiz = luaL_optunsigned(L, 1, DNS_P_QBUFSIZ);
811 	} else {
812 		data = luaL_checklstring(L, 1, &datasiz);
813 		prepbufsiz = luaL_optunsigned(L, 2, datasiz);
814 	}
815 
816 	size = dns_p_calcsize(prepbufsiz);
817 	P = memset(lua_newuserdata(L, size), '\0', size);
818 	luaL_setmetatable(L, PACKET_CLASS);
819 
820 	dns_p_init(P, size);
821 
822 	if (data)
823 		pkt_reload(P, data, datasiz);
824 
825 	return 1;
826 } /* pkt_new() */
827 
828 
pkt_type(lua_State * L)829 static int pkt_type(lua_State *L) {
830 	if (luaL_testudata(L, 1, PACKET_CLASS)) {
831 		lua_pushstring(L, "dns packet");
832 	} else {
833 		lua_pushnil(L);
834 	}
835 
836 	return 1;
837 } /* pkt_type() */
838 
839 
pkt_interpose(lua_State * L)840 static int pkt_interpose(lua_State *L) {
841 	return cqs_interpose(L, PACKET_CLASS);
842 } /* pkt_interpose() */
843 
844 
pkt_qid(lua_State * L)845 static int pkt_qid(lua_State *L) {
846 	struct dns_packet *P = luaL_checkudata(L, 1, PACKET_CLASS);
847 
848 	lua_pushinteger(L, ntohs(dns_header(P)->qid));
849 
850 	return 1;
851 } /* pkt_qid() */
852 
853 
pkt_setqid(lua_State * L)854 static int pkt_setqid(lua_State *L) {
855 	struct dns_packet *P = luaL_checkudata(L, 1, PACKET_CLASS);
856 	int qid = luaL_checkint(L, 2);
857 
858 	dns_header(P)->qid = htons(qid);
859 
860 	lua_settop(L, 1);
861 
862 	return 1;
863 } /* pkt_setqid() */
864 
865 
pkt_flags(lua_State * L)866 static int pkt_flags(lua_State *L) {
867 	struct dns_packet *P = luaL_checkudata(L, 1, PACKET_CLASS);
868 	struct dns_header *hdr = dns_header(P);
869 
870 	lua_newtable(L);
871 
872 	lua_pushboolean(L, hdr->qr);
873 	lua_setfield(L, -2, "qr");
874 
875 	lua_pushinteger(L, hdr->opcode);
876 	lua_setfield(L, -2, "opcode");
877 
878 	lua_pushboolean(L, hdr->aa);
879 	lua_setfield(L, -2, "aa");
880 
881 	lua_pushboolean(L, hdr->tc);
882 	lua_setfield(L, -2, "tc");
883 
884 	lua_pushboolean(L, hdr->rd);
885 	lua_setfield(L, -2, "rd");
886 
887 	lua_pushboolean(L, hdr->ra);
888 	lua_setfield(L, -2, "ra");
889 
890 	lua_pushinteger(L, hdr->unused);
891 	lua_setfield(L, -2, "z");
892 
893 	lua_pushinteger(L, hdr->rcode);
894 	lua_setfield(L, -2, "rcode");
895 
896 	return 1;
897 } /* pkt_flags() */
898 
899 
900 #define pkt_isflag(a, b) (0 == strcmp((a), (b)))
901 
pkt_tobool(lua_State * L,int index)902 static _Bool pkt_tobool(lua_State *L, int index) {
903 	if (lua_isnumber(L, index)) {
904 		return lua_tointeger(L, index);
905 	} else {
906 		return lua_toboolean(L, index);
907 	}
908 } /* pkt_tobool() */
909 
pkt_setflags(lua_State * L)910 static int pkt_setflags(lua_State *L) {
911 	struct dns_packet *P = luaL_checkudata(L, 1, PACKET_CLASS);
912 	struct dns_header *hdr = dns_header(P);
913 
914 	if (lua_isnumber(L, 2)) {
915 		int flags = luaL_checkint(L, 2);
916 
917 		hdr->qr = 0x01 & (flags >> 15);
918 		hdr->opcode = 0x0f & (flags >> 11);
919 		hdr->aa = 0x01 & (flags >> 10);
920 		hdr->tc = 0x01 & (flags >> 9);
921 		hdr->rd = 0x01 & (flags >> 8);
922 		hdr->ra = 0x01 & (flags >> 7);
923 		hdr->unused = 0x07 & (flags >> 4);
924 		hdr->rcode = 0x0f & (flags >> 0);
925 	} else {
926 		luaL_checktype(L, 2, LUA_TTABLE);
927 
928 		for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
929 			const char *flag = luaL_checkstring(L, -2);
930 
931 			if (pkt_isflag(flag, "qr")) {
932 				hdr->qr = pkt_tobool(L, -1);
933 			} else if (pkt_isflag(flag, "opcode")) {
934 				hdr->opcode = luaL_checkint(L, -1);
935 			} else if (pkt_isflag(flag, "aa")) {
936 				hdr->aa = pkt_tobool(L, -1);
937 			} else if (pkt_isflag(flag, "tc")) {
938 				hdr->tc = pkt_tobool(L, -1);
939 			} else if (pkt_isflag(flag, "rd")) {
940 				hdr->rd = pkt_tobool(L, -1);
941 			} else if (pkt_isflag(flag, "ra")) {
942 				hdr->ra = pkt_tobool(L, -1);
943 			} else if (pkt_isflag(flag, "z")) {
944 				hdr->unused = luaL_checkint(L, -1);
945 			} else if (pkt_isflag(flag, "rcode")) {
946 				hdr->rcode = luaL_checkint(L, -1);
947 			}
948 		}
949 	}
950 
951 	lua_settop(L, 1);
952 
953 	return 1;
954 } /* pkt_setflags() */
955 
956 
pkt_push(lua_State * L)957 static int pkt_push(lua_State *L) {
958 	struct dns_packet *P = luaL_checkudata(L, 1, PACKET_CLASS);
959 	int section = luaL_checkint(L, 2);
960 	size_t namelen;
961 	const char *name = luaL_checklstring(L, 3, &namelen);
962 	int type = luaL_optint(L, 4, DNS_T_A);
963 	int class = luaL_optint(L, 5, DNS_C_IN);
964 	int error;
965 
966 	luaL_argcheck(L, section == DNS_S_QUESTION, 2, "pushing RDATA not yet supported");
967 
968 	if ((error = dns_p_push(P, section, name, namelen, type, class, 0, NULL)))
969 		return lua_pushnil(L), lua_pushinteger(L, error), 2;
970 
971 	lua_settop(L, 1);
972 
973 	return 1;
974 } /* pkt_push() */
975 
976 
pkt_count(lua_State * L)977 static int pkt_count(lua_State *L) {
978 	struct dns_packet *P = luaL_checkudata(L, 1, PACKET_CLASS);
979 	int flags = luaL_optint(L, 2, DNS_S_ALL);
980 
981 	lua_pushinteger(L, dns_p_count(P, flags));
982 
983 	return 1;
984 } /* pkt_count() */
985 
986 
pkt_next(lua_State * L)987 static int pkt_next(lua_State *L) {
988 	struct dns_packet *P = lua_touserdata(L, lua_upvalueindex(1));
989 	struct dns_rr_i *rr_i = lua_touserdata(L, lua_upvalueindex(2));
990 	struct dns_rr rr;
991 	int error = 0;
992 
993 	if (!dns_rr_grep(&rr, 1, rr_i, P, &error))
994 		return (error)? luaL_error(L, "dns.packet:grep: %s", cqs_strerror(error)) : 0;
995 
996 	rr_push(L, &rr, P);
997 
998 	return 1;
999 } /* pkt_next() */
1000 
pkt_grep(lua_State * L)1001 static int pkt_grep(lua_State *L) {
1002 	struct dns_packet *P = luaL_checkudata(L, 1, PACKET_CLASS);
1003 	struct dns_rr_i *rr_i;
1004 
1005 	lua_settop(L, 2);
1006 
1007 	lua_pushvalue(L, 1);
1008 	rr_i = memset(lua_newuserdata(L, sizeof *rr_i), '\0', sizeof *rr_i);
1009 	rr_i = dns_rr_i_init(rr_i, P);
1010 
1011 	if (!lua_isnil(L, 2)) {
1012 		luaL_checktype(L, 2, LUA_TTABLE);
1013 
1014 		rr_i->section = optfint(L, 2, "section", 0);
1015 		rr_i->type = optfint(L, 2, "type", 0);
1016 		rr_i->class = optfint(L, 2, "class", 0);
1017 
1018 		lua_getfield(L, 2, "name");
1019 		if (!(rr_i->name = luaL_optstring(L, -1, NULL)))
1020 			lua_pop(L, 1);
1021 	}
1022 
1023 	lua_pushcclosure(L, &pkt_next, lua_gettop(L) - 2);
1024 
1025 	return 1;
1026 } /* pkt_grep() */
1027 
1028 
pkt_load(lua_State * L)1029 static int pkt_load(lua_State *L) {
1030 	struct dns_packet *P = luaL_checkudata(L, 1, PACKET_CLASS);
1031 	size_t size;
1032 	const char *data = luaL_checklstring(L, 2, &size);
1033 
1034 	pkt_reload(P, data, size);
1035 
1036 	lua_settop(L, 1);
1037 
1038 	return 1;
1039 } /* pkt_load() */
1040 
1041 
1042 /* like Lua string.dump, which has opposite meaning from dns.c usage */
pkt_dump(lua_State * L)1043 static int pkt_dump(lua_State *L) {
1044 	struct dns_packet *P = luaL_checkudata(L, 1, PACKET_CLASS);
1045 
1046 	lua_pushlstring(L, (char *)P->data, P->end);
1047 
1048 	return 1;
1049 } /* pkt_dump() */
1050 
1051 
1052 /* FIXME: Potential memory leak on Lua panic. */
pkt__tostring(lua_State * L)1053 static int pkt__tostring(lua_State *L) {
1054 	struct dns_packet *P = luaL_checkudata(L, 1, PACKET_CLASS);
1055 	char line[1024];
1056 	luaL_Buffer B;
1057 	FILE *fp;
1058 
1059 	if (!(fp = tmpfile()))
1060 		return luaL_error(L, "tmpfile: %s", cqs_strerror(errno));
1061 
1062 	dns_p_dump(P, fp);
1063 
1064 	luaL_buffinit(L, &B);
1065 
1066 	rewind(fp);
1067 
1068 	while (fgets(line, sizeof line, fp))
1069 		luaL_addstring(&B, line);
1070 
1071 	fclose(fp);
1072 
1073 	luaL_pushresult(&B);
1074 
1075 	return 1;
1076 } /* pkt__tostring() */
1077 
1078 
1079 static const luaL_Reg pkt_methods[] = {
1080 	{ "qid",      &pkt_qid },
1081 	{ "setqid",   &pkt_setqid },
1082 	{ "flags",    &pkt_flags },
1083 	{ "setflags", &pkt_setflags },
1084 	{ "push",     &pkt_push },
1085 	{ "count",    &pkt_count },
1086 	{ "grep",     &pkt_grep },
1087 	{ "load",     &pkt_load },
1088 	{ "dump",     &pkt_dump },
1089 	{ NULL,       NULL },
1090 }; /* pkt_methods[] */
1091 
1092 static const luaL_Reg pkt_metatable[] = {
1093 	{ "__tostring", &pkt__tostring },
1094 	{ NULL,         NULL }
1095 }; /* pkt_metatable[] */
1096 
1097 static const luaL_Reg pkt_globals[] = {
1098 	{ "new",       &pkt_new },
1099 	{ "type",      &pkt_type },
1100 	{ "interpose", &pkt_interpose },
1101 	{ NULL,        NULL }
1102 };
1103 
luaopen__cqueues_dns_packet(lua_State * L)1104 int luaopen__cqueues_dns_packet(lua_State *L) {
1105 	static const struct cqs_macro section[] = {
1106 		{ "QUESTION", DNS_S_QD }, { "ANSWER", DNS_S_AN },
1107 		{ "AUTHORITY", DNS_S_NS }, { "ADDITIONAL", DNS_S_AR },
1108 	};
1109 	static const struct cqs_macro shortsec[] = {
1110 		{ "QD", DNS_S_QD }, { "AN", DNS_S_AN },
1111 		{ "NS", DNS_S_NS }, { "AR", DNS_S_AR },
1112 	};
1113 	static const struct cqs_macro opcode[] = {
1114 		{ "QUERY", DNS_OP_QUERY }, { "IQUERY", DNS_OP_IQUERY },
1115 		{ "STATUS", DNS_OP_STATUS }, { "NOTIFY", DNS_OP_NOTIFY },
1116 		{ "UPDATE", DNS_OP_UPDATE },
1117 	};
1118 	static const struct cqs_macro rcode[] = {
1119 		{ "NOERROR", DNS_RC_NOERROR }, { "FORMERR", DNS_RC_FORMERR },
1120 		{ "SERVFAIL", DNS_RC_SERVFAIL }, { "NXDOMAIN", DNS_RC_NXDOMAIN },
1121 		{ "NOTIMP", DNS_RC_NOTIMP }, { "REFUSED", DNS_RC_REFUSED },
1122 		{ "YXDOMAIN", DNS_RC_YXDOMAIN }, { "YXRRSET", DNS_RC_YXRRSET },
1123 		{ "NXRRSET", DNS_RC_NXRRSET }, { "NOTAUTH", DNS_RC_NOTAUTH },
1124 		{ "NOTZONE", DNS_RC_NOTZONE },
1125 	};
1126 	static const struct cqs_macro other[] = {
1127 		{ "QBUFSIZ", DNS_P_QBUFSIZ },
1128 	};
1129 
1130 	cqs_newmetatable(L, PACKET_CLASS, pkt_methods, pkt_metatable, 0);
1131 
1132 	luaL_newlib(L, pkt_globals);
1133 
1134 	lua_newtable(L);
1135 	cqs_setmacros(L, -1, section, countof(section), 1);
1136 	cqs_setmacros(L, -1, shortsec, countof(shortsec), 0);
1137 	lua_setfield(L, -2, "section");
1138 
1139 	lua_newtable(L);
1140 	cqs_setmacros(L, -1, opcode, countof(opcode), 1);
1141 	lua_setfield(L, -2, "opcode");
1142 
1143 	lua_newtable(L);
1144 	cqs_setmacros(L, -1, rcode, countof(rcode), 1);
1145 	lua_setfield(L, -2, "rcode");
1146 
1147 	cqs_setmacros(L, -1, other, countof(other), 0);
1148 
1149 	return 1;
1150 } /* luaopen__cqueues_dns_packet() */
1151 
1152 
1153 /*
1154  * R E S O L V . C O N F  B I N D I N G S
1155  *
1156  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1157 
1158 #define RESCONF_RESOLV_CONF   0
1159 #define RESCONF_NSSWITCH_CONF 1
1160 
1161 
resconf_new(lua_State * L)1162 static int resconf_new(lua_State *L) {
1163 	struct dns_resolv_conf **resconf = lua_newuserdata(L, sizeof *resconf);
1164 	int error;
1165 
1166 	*resconf = 0;
1167 
1168 	if (!(*resconf = dns_resconf_open(&error)))
1169 		return lua_pushboolean(L, 0), lua_pushinteger(L, error), 2;
1170 
1171 	luaL_setmetatable(L, RESCONF_CLASS);
1172 
1173 	return 1;
1174 } /* resconf_new() */
1175 
1176 
resconf_stub(lua_State * L)1177 static int resconf_stub(lua_State *L) {
1178 	struct dns_resolv_conf **resconf = lua_newuserdata(L, sizeof *resconf);
1179 	int error;
1180 
1181 	*resconf = 0;
1182 
1183 	if (!(*resconf = dns_resconf_local(&error)))
1184 		return lua_pushboolean(L, 0), lua_pushinteger(L, error), 2;
1185 
1186 	luaL_setmetatable(L, RESCONF_CLASS);
1187 
1188 	return 1;
1189 } /* resconf_stub() */
1190 
1191 
resconf_root(lua_State * L)1192 static int resconf_root(lua_State *L) {
1193 	struct dns_resolv_conf **resconf = lua_newuserdata(L, sizeof *resconf);
1194 	int error;
1195 
1196 	*resconf = 0;
1197 
1198 	if (!(*resconf = dns_resconf_root(&error)))
1199 		return lua_pushboolean(L, 0), lua_pushinteger(L, error), 2;
1200 
1201 	luaL_setmetatable(L, RESCONF_CLASS);
1202 
1203 	return 1;
1204 } /* resconf_root() */
1205 
1206 
resconf_interpose(lua_State * L)1207 static int resconf_interpose(lua_State *L) {
1208 	return cqs_interpose(L, RESCONF_CLASS);
1209 } /* resconf_interpose() */
1210 
1211 
resconf_check(lua_State * L,int index)1212 static struct dns_resolv_conf *resconf_check(lua_State *L, int index) {
1213 	return *(struct dns_resolv_conf **)luaL_checkudata(L, index, RESCONF_CLASS);
1214 } /* resconf_check() */
1215 
1216 
resconf_test(lua_State * L,int index)1217 static struct dns_resolv_conf *resconf_test(lua_State *L, int index) {
1218 	struct dns_resolv_conf **resconf = luaL_testudata(L, index, RESCONF_CLASS);
1219 	return (resconf)? *resconf : 0;
1220 } /* resconf_test() */
1221 
1222 
resconf_type(lua_State * L)1223 static int resconf_type(lua_State *L) {
1224 	if (resconf_test(L, 1)) {
1225 		lua_pushstring(L, "dns config");
1226 	} else {
1227 		lua_pushnil(L);
1228 	}
1229 
1230 	return 1;
1231 } /* resconf_type() */
1232 
1233 
resconf_getns(lua_State * L)1234 static int resconf_getns(lua_State *L) {
1235 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1236 
1237 	lua_newtable(L);
1238 
1239 	for (unsigned i = 0; i < countof(resconf->nameserver); i++) {
1240 		union { struct sockaddr_storage *other; struct sockaddr_in *in; struct sockaddr_in6 *in6; } any;
1241 		char ns[INET6_ADDRSTRLEN + 1] = "";
1242 		int port;
1243 
1244 		any.other = &resconf->nameserver[i];
1245 
1246 		switch (any.other->ss_family) {
1247 		case AF_INET:
1248 			inet_ntop(AF_INET, &any.in->sin_addr, ns, sizeof ns);
1249 			port = ntohs(any.in->sin_port);
1250 			break;
1251 		case AF_INET6:
1252 			inet_ntop(AF_INET6, &any.in6->sin6_addr, ns, sizeof ns);
1253 			port = ntohs(any.in6->sin6_port);
1254 			break;
1255 		default:
1256 			continue;
1257 		}
1258 
1259 		if (port && port != 53)
1260 			lua_pushfstring(L, "[%s]:%d", ns, port);
1261 		else
1262 			lua_pushstring(L, ns);
1263 
1264 		lua_rawseti(L, -2, i + 1);
1265 	}
1266 
1267 	return 1;
1268 } /* resconf_getns() */
1269 
1270 
resconf_setns(lua_State * L)1271 static int resconf_setns(lua_State *L) {
1272 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1273 
1274 	luaL_checktype(L, 2, LUA_TTABLE);
1275 
1276 	for (unsigned i = 0; i < countof(resconf->nameserver); i++) {
1277 		const char *ns;
1278 		int error;
1279 
1280 		lua_rawgeti(L, 2, i + 1);
1281 
1282 		if ((ns = luaL_optstring(L, -1, 0))) {
1283 			if ((error = dns_resconf_pton(&resconf->nameserver[i], ns)))
1284 				return luaL_error(L, "%s: %s", ns, cqs_strerror(error));
1285 		} else {
1286 			memset(&resconf->nameserver[i], 0, sizeof resconf->nameserver[i]);
1287 			resconf->nameserver[i].ss_family = AF_UNSPEC;
1288 		}
1289 
1290 		lua_pop(L, 1);
1291 	}
1292 
1293 	return lua_pushboolean(L, 1), 1;
1294 } /* resconf_setns() */
1295 
1296 
resconf_getsearch(lua_State * L)1297 static int resconf_getsearch(lua_State *L) {
1298 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1299 
1300 	lua_newtable(L);
1301 
1302 	for (unsigned i = 0; i < countof(resconf->search) && *resconf->search[i]; i++) {
1303 		lua_pushstring(L, resconf->search[i]);
1304 		lua_rawseti(L, -2, i + 1);
1305 	}
1306 
1307 	return 1;
1308 } /* resconf_getsearch() */
1309 
1310 
resconf_setsearch(lua_State * L)1311 static int resconf_setsearch(lua_State *L) {
1312 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1313 
1314 	luaL_checktype(L, 2, LUA_TTABLE);
1315 
1316 	for (unsigned i = 0; i < countof(resconf->search); i++) {
1317 		const char *dn;
1318 
1319 		lua_rawgeti(L, 2, i + 1);
1320 
1321 		if ((dn = luaL_optstring(L, -1, 0))) {
1322 			dns_strlcpy(resconf->search[i], dn, sizeof resconf->search[i]);
1323 		} else {
1324 			memset(resconf->search[i], 0, sizeof resconf->search[i]);
1325 		}
1326 
1327 		lua_pop(L, 1);
1328 	}
1329 
1330 	return lua_pushboolean(L, 1), 1;
1331 } /* resconf_setsearch() */
1332 
1333 
resconf_getlookup(lua_State * L)1334 static int resconf_getlookup(lua_State *L) {
1335 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1336 
1337 	lua_newtable(L);
1338 
1339 	for (unsigned i = 0; i < countof(resconf->lookup) && resconf->lookup[i]; i++) {
1340 		switch (resconf->lookup[i]) {
1341 		case 'f': case 'F':
1342 			lua_pushliteral(L, "file");
1343 			break;
1344 		case 'b': case 'B':
1345 			lua_pushliteral(L, "bind");
1346 			break;
1347 		case 'c': case 'C':
1348 			lua_pushliteral(L, "cache");
1349 			break;
1350 		default:
1351 			continue;
1352 		}
1353 
1354 		lua_rawseti(L, -2, i + 1);
1355 	}
1356 
1357 	return 1;
1358 } /* resconf_getlookup() */
1359 
1360 
resconf_setlookup(lua_State * L)1361 static int resconf_setlookup(lua_State *L) {
1362 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1363 
1364 	luaL_checktype(L, 2, LUA_TTABLE);
1365 
1366 	memset(resconf->lookup, 0, sizeof resconf->lookup);
1367 
1368 	for (unsigned i = 0; i < countof(resconf->lookup); i++) {
1369 		const char *lu;
1370 
1371 		lua_rawgeti(L, 2, i + 1);
1372 
1373 		if ((lu = luaL_optstring(L, -1, 0))) {
1374 			switch (*lu) {
1375 			case 'f': case 'F':
1376 				resconf->lookup[i] = 'f';
1377 				break;
1378 			case 'b': case 'B':
1379 				resconf->lookup[i] = 'b';
1380 				break;
1381 			case 'c': case 'C':
1382 				resconf->lookup[i] = 'c';
1383 				break;
1384 			}
1385 		}
1386 
1387 		lua_pop(L, 1);
1388 	}
1389 
1390 	return lua_pushboolean(L, 1), 1;
1391 } /* resconf_setlookup() */
1392 
1393 
resconf_getopts(lua_State * L)1394 static int resconf_getopts(lua_State *L) {
1395 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1396 
1397 	lua_newtable(L);
1398 
1399 	lua_pushboolean(L, resconf->options.edns0);
1400 	lua_setfield(L, -2, "edns0");
1401 
1402 	lua_pushinteger(L, resconf->options.ndots);
1403 	lua_setfield(L, -2, "ndots");
1404 
1405 	lua_pushinteger(L, resconf->options.timeout);
1406 	lua_setfield(L, -2, "timeout");
1407 
1408 	lua_pushinteger(L, resconf->options.attempts);
1409 	lua_setfield(L, -2, "attempts");
1410 
1411 	lua_pushboolean(L, resconf->options.rotate);
1412 	lua_setfield(L, -2, "rotate");
1413 
1414 	lua_pushboolean(L, resconf->options.recurse);
1415 	lua_setfield(L, -2, "recurse");
1416 
1417 	lua_pushboolean(L, resconf->options.smart);
1418 	lua_setfield(L, -2, "smart");
1419 
1420 	lua_pushinteger(L, resconf->options.tcp);
1421 	lua_setfield(L, -2, "tcp");
1422 
1423 	return 1;
1424 } /* resconf_getopts() */
1425 
1426 
resconf_setopts(lua_State * L)1427 static int resconf_setopts(lua_State *L) {
1428 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1429 
1430 	luaL_checktype(L, 2, LUA_TTABLE);
1431 
1432 	resconf->options.edns0 = optfbool(L, 2, "edns0", resconf->options.edns0);
1433 	resconf->options.ndots = optfint(L, 2, "ndots", resconf->options.ndots);
1434 	resconf->options.timeout = optfint(L, 2, "timeout", resconf->options.timeout);
1435 	resconf->options.attempts = optfint(L, 2, "attempts", resconf->options.attempts);
1436 	resconf->options.rotate = optfbool(L, 2, "rotate", resconf->options.rotate);
1437 	resconf->options.recurse = optfbool(L, 2, "recurse", resconf->options.recurse);
1438 	resconf->options.smart = optfbool(L, 2, "smart", resconf->options.smart);
1439 	resconf->options.tcp = optfint(L, 2, "tcp", resconf->options.tcp);
1440 
1441 	return lua_pushboolean(L, 1), 1;
1442 } /* resconf_setopts() */
1443 
1444 
resconf_getiface(lua_State * L)1445 static int resconf_getiface(lua_State *L) {
1446 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1447 	union { struct sockaddr_storage *other; struct sockaddr_in *in; struct sockaddr_in6 *in6; } any;
1448 	char ipbuf[INET6_ADDRSTRLEN + 1];
1449 	const char *ip = 0;
1450 	int port = 0;
1451 
1452 	any.other = &resconf->iface;
1453 
1454 	switch (any.other->ss_family) {
1455 	case AF_INET:
1456 		ip = inet_ntop(AF_INET, &any.in->sin_addr, ipbuf, sizeof ipbuf);
1457 		port = ntohs(any.in->sin_port);
1458 		break;
1459 	case AF_INET6:
1460 		ip = inet_ntop(AF_INET6, &any.in6->sin6_addr, ipbuf, sizeof ipbuf);
1461 		port = ntohs(any.in6->sin6_port);
1462 		break;
1463 	}
1464 
1465 	if (!ip)
1466 		return 0;
1467 
1468 	if (port && port != 53)
1469 		lua_pushfstring(L, "[%s]:%d", ip, port);
1470 	else
1471 		lua_pushstring(L, ip);
1472 
1473 	return 1;
1474 } /* resconf_getiface() */
1475 
1476 
resconf_setiface(lua_State * L)1477 static int resconf_setiface(lua_State *L) {
1478 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1479 	const char *ip = luaL_checkstring(L, 2);
1480 	int error;
1481 
1482 	if ((error = dns_resconf_pton(&resconf->iface, ip)))
1483 		return luaL_error(L, "%s: %s", ip, cqs_strerror(error));
1484 
1485 	return lua_pushboolean(L, 1), 1;
1486 } /* resconf_setiface */
1487 
1488 
resconf_loadfile(lua_State * L)1489 static int resconf_loadfile(lua_State *L) {
1490 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1491 	luaL_Stream *file = luaL_checkudata(L, 2, LUA_FILEHANDLE);
1492 	int syntax = luaL_optint(L, 3, RESCONF_RESOLV_CONF);
1493 	int error;
1494 
1495 	switch (syntax) {
1496 	case RESCONF_NSSWITCH_CONF:
1497 		error = dns_nssconf_loadfile(resconf, file->f);
1498 		break;
1499 	default:
1500 		error = dns_resconf_loadfile(resconf, file->f);
1501 		break;
1502 	}
1503 
1504 	if (error)
1505 		return lua_pushboolean(L, 0), lua_pushinteger(L, error), 2;
1506 
1507 	return lua_pushboolean(L, 1), 1;
1508 } /* resconf_loadfile() */
1509 
1510 
resconf_loadpath(lua_State * L)1511 static int resconf_loadpath(lua_State *L) {
1512 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1513 	const char *path = luaL_checkstring(L, 2);
1514 	int syntax = luaL_optint(L, 3, RESCONF_RESOLV_CONF);
1515 	int error;
1516 
1517 	switch (syntax) {
1518 	case RESCONF_NSSWITCH_CONF:
1519 		error = dns_nssconf_loadpath(resconf, path);
1520 		break;
1521 	default:
1522 		error = dns_resconf_loadpath(resconf, path);
1523 		break;
1524 	}
1525 
1526 	if (error)
1527 		return lua_pushboolean(L, 0), lua_pushinteger(L, error), 2;
1528 
1529 	return lua_pushboolean(L, 1), 1;
1530 } /* resconf_loadpath() */
1531 
1532 
resconf__next(lua_State * L)1533 static int resconf__next(lua_State *L) {
1534 	struct dns_resolv_conf *resconf = *(struct dns_resolv_conf **)lua_touserdata(L, lua_upvalueindex(1));
1535 	size_t len;
1536 	const char *qn = lua_tolstring(L, lua_upvalueindex(2), &len);
1537 	dns_resconf_i_t *i = lua_touserdata(L, lua_upvalueindex(3));
1538 	char dn[DNS_D_MAXNAME + 1];
1539 
1540 	if (!(len = dns_resconf_search(dn, sizeof dn, qn, len, resconf, i)))
1541 		return 0;
1542 
1543 	lua_pushlstring(L, dn, len);
1544 
1545 	return 1;
1546 } /* resconf__next() */
1547 
1548 
resconf_search(lua_State * L)1549 static int resconf_search(lua_State *L) {
1550 	dns_resconf_i_t *i;
1551 
1552 	resconf_check(L, 1);
1553 
1554 	lua_settop(L, 2);
1555 	luaL_checktype(L, 2, LUA_TSTRING);
1556 
1557 	i = lua_newuserdata(L, sizeof *i);
1558 	*i = 0;
1559 
1560 	lua_pushcclosure(L, &resconf__next, 3);
1561 
1562 	return 1;
1563 } /* resconf_search() */
1564 
1565 
1566 /* FIXME: Potential memory leak on Lua panic. */
resconf__tostring(lua_State * L)1567 static int resconf__tostring(lua_State *L) {
1568 	struct dns_resolv_conf *resconf = resconf_check(L, 1);
1569 	char line[1024];
1570 	luaL_Buffer B;
1571 	FILE *fp;
1572 
1573 	if (!(fp = tmpfile()))
1574 		return luaL_error(L, "tmpfile: %s", cqs_strerror(errno));
1575 
1576 	dns_resconf_dump(resconf, fp);
1577 
1578 	luaL_buffinit(L, &B);
1579 
1580 	rewind(fp);
1581 
1582 	while (fgets(line, sizeof line, fp))
1583 		luaL_addstring(&B, line);
1584 
1585 	fclose(fp);
1586 
1587 	luaL_pushresult(&B);
1588 
1589 	return 1;
1590 } /* resconf__tostring() */
1591 
1592 
resconf__gc(lua_State * L)1593 static int resconf__gc(lua_State *L) {
1594 	struct dns_resolv_conf **resconf = luaL_checkudata(L, 1, RESCONF_CLASS);
1595 
1596 	dns_resconf_close(*resconf);
1597 	*resconf = 0;
1598 
1599 	return 0;
1600 } /* resconf__gc() */
1601 
1602 
1603 static const luaL_Reg resconf_methods[] = {
1604 	{ "getns",     &resconf_getns },
1605 	{ "setns",     &resconf_setns },
1606 	{ "getsearch", &resconf_getsearch },
1607 	{ "setsearch", &resconf_setsearch },
1608 	{ "getlookup", &resconf_getlookup },
1609 	{ "setlookup", &resconf_setlookup },
1610 	{ "getopts",   &resconf_getopts },
1611 	{ "setopts",   &resconf_setopts },
1612 	{ "getiface",  &resconf_getiface },
1613 	{ "setiface",  &resconf_setiface },
1614 	{ "loadfile",  &resconf_loadfile },
1615 	{ "loadpath",  &resconf_loadpath },
1616 	{ "search",    &resconf_search },
1617 	{ NULL,        NULL },
1618 }; /* resconf_methods[] */
1619 
1620 static const luaL_Reg resconf_metatable[] = {
1621 	{ "__tostring", &resconf__tostring },
1622 	{ "__gc",       &resconf__gc },
1623 	{ NULL,         NULL }
1624 }; /* resconf_metatable[] */
1625 
1626 static const luaL_Reg resconf_globals[] = {
1627 	{ "new",       &resconf_new },
1628 	{ "stub",      &resconf_stub },
1629 	{ "root",      &resconf_root },
1630 	{ "interpose", &resconf_interpose },
1631 	{ "type",      &resconf_type },
1632 	{ NULL,        NULL }
1633 };
1634 
luaopen__cqueues_dns_config(lua_State * L)1635 int luaopen__cqueues_dns_config(lua_State *L) {
1636 	cqs_newmetatable(L, RESCONF_CLASS, resconf_methods, resconf_metatable, 0);
1637 
1638 	luaL_newlib(L, resconf_globals);
1639 
1640 	lua_pushinteger(L, DNS_RESCONF_TCP_ENABLE);
1641 	lua_setfield(L, -2, "TCP_ENABLE");
1642 
1643 	lua_pushinteger(L, DNS_RESCONF_TCP_ONLY);
1644 	lua_setfield(L, -2, "TCP_ONLY");
1645 
1646 	lua_pushinteger(L, DNS_RESCONF_TCP_DISABLE);
1647 	lua_setfield(L, -2, "TCP_DISABLE");
1648 
1649 	lua_pushinteger(L, RESCONF_RESOLV_CONF);
1650 	lua_setfield(L, -2, "RESOLV_CONF");
1651 
1652 	lua_pushinteger(L, RESCONF_NSSWITCH_CONF);
1653 	lua_setfield(L, -2, "NSSWITCH_CONF");
1654 
1655 	return 1;
1656 } /* luaopen__cqueues_dns_config() */
1657 
1658 
1659 /*
1660  * H O S T S  B I N D I N G S
1661  *
1662  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1663 
hosts_new(lua_State * L)1664 static int hosts_new(lua_State *L) {
1665 	struct dns_hosts **hosts = lua_newuserdata(L, sizeof *hosts);
1666 	int error;
1667 
1668 	*hosts = 0;
1669 
1670 	if (!(*hosts = dns_hosts_open(&error)))
1671 		return lua_pushboolean(L, 0), lua_pushinteger(L, error), 2;
1672 
1673 	luaL_setmetatable(L, HOSTS_CLASS);
1674 
1675 	return 1;
1676 } /* hosts_new() */
1677 
1678 
hosts_interpose(lua_State * L)1679 static int hosts_interpose(lua_State *L) {
1680 	return cqs_interpose(L, HOSTS_CLASS);
1681 } /* hosts_interpose() */
1682 
1683 
hosts_check(lua_State * L,int index)1684 static struct dns_hosts *hosts_check(lua_State *L, int index) {
1685 	return *(struct dns_hosts **)luaL_checkudata(L, index, HOSTS_CLASS);
1686 } /* hosts_check() */
1687 
1688 
hosts_test(lua_State * L,int index)1689 static struct dns_hosts *hosts_test(lua_State *L, int index) {
1690 	struct dns_hosts **hosts = luaL_testudata(L, index, HOSTS_CLASS);
1691 	return (hosts)? *hosts : 0;
1692 } /* hosts_test() */
1693 
1694 
hosts_type(lua_State * L)1695 static int hosts_type(lua_State *L) {
1696 	if (hosts_test(L, 1)) {
1697 		lua_pushstring(L, "dns hosts");
1698 	} else {
1699 		lua_pushnil(L);
1700 	}
1701 
1702 	return 1;
1703 } /* hosts_type() */
1704 
1705 
hosts_loadfile(lua_State * L)1706 static int hosts_loadfile(lua_State *L) {
1707 	struct dns_hosts *hosts = hosts_check(L, 1);
1708 	luaL_Stream *file = luaL_checkudata(L, 2, LUA_FILEHANDLE);
1709 	int error;
1710 
1711 	if ((error = dns_hosts_loadfile(hosts, file->f)))
1712 		return lua_pushboolean(L, 0), lua_pushinteger(L, error), 2;
1713 
1714 	return lua_pushboolean(L, 1), 1;
1715 } /* hosts_loadfile() */
1716 
1717 
hosts_loadpath(lua_State * L)1718 static int hosts_loadpath(lua_State *L) {
1719 	struct dns_hosts *hosts = hosts_check(L, 1);
1720 	const char *path = luaL_checkstring(L, 2);
1721 	int error;
1722 
1723 	if ((error = dns_hosts_loadpath(hosts, path)))
1724 		return lua_pushboolean(L, 0), lua_pushinteger(L, error), 2;
1725 
1726 	return lua_pushboolean(L, 1), 1;
1727 } /* hosts_loadpath() */
1728 
1729 
hosts_insert(lua_State * L)1730 static int hosts_insert(lua_State *L) {
1731 	struct dns_hosts *hosts = hosts_check(L, 1);
1732 	const char *ip = luaL_checkstring(L, 2);
1733 	const char *dn = luaL_checkstring(L, 3);
1734 	_Bool alias = (!lua_isnoneornil(L, 4))? lua_toboolean(L, 4) : 0;
1735 	union { struct sockaddr_storage other; struct sockaddr_in in; struct sockaddr_in6 in6; } any;
1736 	int error;
1737 
1738 	if ((error = dns_resconf_pton(&any.other, ip)))
1739 		goto error;
1740 
1741 	switch (any.other.ss_family) {
1742 	case AF_INET:
1743 		if ((error = dns_hosts_insert(hosts, AF_INET, &any.in.sin_addr, dn, alias)))
1744 			goto error;
1745 		break;
1746 	case AF_INET6:
1747 		if ((error = dns_hosts_insert(hosts, AF_INET6, &any.in6.sin6_addr, dn, alias)))
1748 			goto error;
1749 		break;
1750 	default:
1751 		break;
1752 	}
1753 
1754 	return lua_pushboolean(L, 1), 1;
1755 error:
1756 	return luaL_error(L, "%s: %s", ip, cqs_strerror(error));
1757 } /* hosts_insert() */
1758 
1759 
1760 /* FIXME: Potential memory leak on Lua panic. */
hosts__tostring(lua_State * L)1761 static int hosts__tostring(lua_State *L) {
1762 	struct dns_hosts *hosts = hosts_check(L, 1);
1763 	char line[1024];
1764 	luaL_Buffer B;
1765 	FILE *fp;
1766 
1767 	if (!(fp = tmpfile()))
1768 		return luaL_error(L, "tmpfile: %s", cqs_strerror(errno));
1769 
1770 	dns_hosts_dump(hosts, fp);
1771 
1772 	luaL_buffinit(L, &B);
1773 
1774 	rewind(fp);
1775 
1776 	while (fgets(line, sizeof line, fp))
1777 		luaL_addstring(&B, line);
1778 
1779 	fclose(fp);
1780 
1781 	luaL_pushresult(&B);
1782 
1783 	return 1;
1784 } /* hosts__tostring() */
1785 
1786 
hosts__gc(lua_State * L)1787 static int hosts__gc(lua_State *L) {
1788 	struct dns_hosts **hosts = luaL_checkudata(L, 1, HOSTS_CLASS);
1789 
1790 	dns_hosts_close(*hosts);
1791 	*hosts = 0;
1792 
1793 	return 0;
1794 } /* hosts__gc() */
1795 
1796 
1797 static const luaL_Reg hosts_methods[] = {
1798 	{ "loadfile", &hosts_loadfile },
1799 	{ "loadpath", &hosts_loadpath },
1800 	{ "insert",   &hosts_insert },
1801 	{ NULL,       NULL },
1802 }; /* hosts_methods[] */
1803 
1804 static const luaL_Reg hosts_metatable[] = {
1805 	{ "__tostring", &hosts__tostring },
1806 	{ "__gc",       &hosts__gc },
1807 	{ NULL,         NULL }
1808 }; /* hosts_metatable[] */
1809 
1810 static const luaL_Reg hosts_globals[] = {
1811 	{ "new",       &hosts_new },
1812 	{ "interpose", &hosts_interpose },
1813 	{ "type",      &hosts_type },
1814 	{ NULL,        NULL }
1815 };
1816 
luaopen__cqueues_dns_hosts(lua_State * L)1817 int luaopen__cqueues_dns_hosts(lua_State *L) {
1818 	// not needed until dns_hosts_query bound
1819 	//cqs_requiref(L, "_cqueues.dns.packet", &luaopen__cqueues_dns_packet, 0);
1820 
1821 	cqs_newmetatable(L, HOSTS_CLASS, hosts_methods, hosts_metatable, 0);
1822 
1823 	luaL_newlib(L, hosts_globals);
1824 
1825 	return 1;
1826 } /* luaopen__cqueues_dns_hosts() */
1827 
1828 
1829 /*
1830  * H I N T S  B I N D I N G S
1831  *
1832  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1833 
hints_new(lua_State * L)1834 static int hints_new(lua_State *L) {
1835 	struct dns_resolv_conf *resconf = resconf_test(L, 1);
1836 	struct dns_hints **hints;
1837 	int error;
1838 
1839 	hints = lua_newuserdata(L, sizeof *hints);
1840 	*hints = 0;
1841 
1842 	if (!(*hints = dns_hints_open(resconf, &error)))
1843 		return lua_pushboolean(L, 0), lua_pushinteger(L, error), 2;
1844 
1845 	luaL_setmetatable(L, HINTS_CLASS);
1846 
1847 	return 1;
1848 } /* hints_new() */
1849 
1850 
hints_root(lua_State * L)1851 static int hints_root(lua_State *L) {
1852 	struct dns_resolv_conf *resconf = resconf_test(L, 1);
1853 	struct dns_hints **hints;
1854 	int error;
1855 
1856 	hints = lua_newuserdata(L, sizeof *hints);
1857 	*hints = 0;
1858 
1859 	if (!(*hints = dns_hints_root(resconf, &error)))
1860 		return lua_pushboolean(L, 0), lua_pushinteger(L, error), 2;
1861 
1862 	luaL_setmetatable(L, HINTS_CLASS);
1863 
1864 	return 1;
1865 } /* hints_root() */
1866 
1867 
hints_stub(lua_State * L)1868 static int hints_stub(lua_State *L) {
1869 	struct dns_resolv_conf *resconf = resconf_test(L, 1);
1870 	struct dns_hints **hints;
1871 	int error;
1872 
1873 	hints = lua_newuserdata(L, sizeof *hints);
1874 	*hints = 0;
1875 
1876 	if (!(*hints = dns_hints_local(resconf, &error)))
1877 		return lua_pushboolean(L, 0), lua_pushinteger(L, error), 2;
1878 
1879 	luaL_setmetatable(L, HINTS_CLASS);
1880 
1881 	return 1;
1882 } /* hints_stub() */
1883 
1884 
hints_interpose(lua_State * L)1885 static int hints_interpose(lua_State *L) {
1886 	return cqs_interpose(L, HINTS_CLASS);
1887 } /* hints_interpose() */
1888 
1889 
hints_check(lua_State * L,int index)1890 static struct dns_hints *hints_check(lua_State *L, int index) {
1891 	return *(struct dns_hints **)luaL_checkudata(L, index, HINTS_CLASS);
1892 } /* hints_check() */
1893 
1894 
hints_test(lua_State * L,int index)1895 static struct dns_hints *hints_test(lua_State *L, int index) {
1896 	struct dns_hints **hints = luaL_testudata(L, index, HINTS_CLASS);
1897 	return (hints)? *hints : 0;
1898 } /* hints_test() */
1899 
1900 
hints_type(lua_State * L)1901 static int hints_type(lua_State *L) {
1902 	if (hints_test(L, 1)) {
1903 		lua_pushstring(L, "dns hints");
1904 	} else {
1905 		lua_pushnil(L);
1906 	}
1907 
1908 	return 1;
1909 } /* hints_type() */
1910 
1911 
hints_insert(lua_State * L)1912 static int hints_insert(lua_State *L) {
1913 	struct dns_hints *hints = hints_check(L, 1);
1914 	const char *zone = luaL_checkstring(L, 2), *ns;
1915 	int priority = luaL_optint(L, 4, 0);
1916 	int error = 0;
1917 
1918 	if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) {
1919 		dns_hints_insert_resconf(hints, zone, resconf_check(L, 3), &error);
1920 	} else {
1921 		ns = luaL_checkstring(L, 3);
1922 		struct sockaddr_storage any;
1923 
1924 		if (!(error = dns_resconf_pton(&any, ns)))
1925 			error = dns_hints_insert(hints, zone, (struct sockaddr *)&any, priority);
1926 	}
1927 
1928 	if (error)
1929 		return luaL_error(L, "%s: %s", zone, cqs_strerror(error));
1930 
1931 	return lua_pushboolean(L, 1), 1;
1932 } /* hints_insert() */
1933 
1934 
hints_next(lua_State * L)1935 static int hints_next(lua_State *L) {
1936 	struct dns_hints *hints = hints_check(L, lua_upvalueindex(1));
1937 	struct dns_hints_i *i = lua_touserdata(L, lua_upvalueindex(3));
1938 	union { struct sockaddr *sa; struct sockaddr_in *in; struct sockaddr_in6 *in6; } any;
1939 	socklen_t salen;
1940 	char ip[INET6_ADDRSTRLEN + 1] = "";
1941 	int port;
1942 
1943 	while (dns_hints_grep(&any.sa, &salen, 1, i, hints)) {
1944 		switch (any.sa->sa_family) {
1945 		case AF_INET:
1946 			inet_ntop(AF_INET, &any.in->sin_addr, ip, sizeof ip);
1947 			port = ntohs(any.in->sin_port);
1948 			break;
1949 		case AF_INET6:
1950 			inet_ntop(AF_INET6, &any.in6->sin6_addr, ip, sizeof ip);
1951 			port = ntohs(any.in6->sin6_port);
1952 			break;
1953 		default:
1954 			continue;
1955 		}
1956 
1957 		if (port && port != 53)
1958 			lua_pushfstring(L, "[%s]:%d", ip, port);
1959 		else
1960 			lua_pushstring(L, ip);
1961 
1962 		return 1;
1963 	}
1964 
1965 	return 0;
1966 } /* hints_next() */
1967 
hints_grep(lua_State * L)1968 static int hints_grep(lua_State *L) {
1969 	struct dns_hints_i *i;
1970 
1971 	hints_check(L, 1);
1972 
1973 	lua_settop(L, 2);
1974 	i = memset(lua_newuserdata(L, sizeof *i), 0, sizeof *i);
1975 	i->zone = luaL_optstring(L, 2, ".");
1976 
1977 	lua_pushcclosure(L, &hints_next, 3);
1978 
1979 	return 1;
1980 } /* hints_grep() */
1981 
1982 
1983 /* FIXME: Potential memory leak on Lua panic. */
hints__tostring(lua_State * L)1984 static int hints__tostring(lua_State *L) {
1985 	struct dns_hints *hints = hints_check(L, 1);
1986 	char line[1024];
1987 	luaL_Buffer B;
1988 	FILE *fp;
1989 
1990 	if (!(fp = tmpfile()))
1991 		return luaL_error(L, "tmpfile: %s", cqs_strerror(errno));
1992 
1993 	dns_hints_dump(hints, fp);
1994 
1995 	luaL_buffinit(L, &B);
1996 
1997 	rewind(fp);
1998 
1999 	while (fgets(line, sizeof line, fp))
2000 		luaL_addstring(&B, line);
2001 
2002 	fclose(fp);
2003 
2004 	luaL_pushresult(&B);
2005 
2006 	return 1;
2007 } /* hints__tostring() */
2008 
2009 
hints__gc(lua_State * L)2010 static int hints__gc(lua_State *L) {
2011 	struct dns_hints **hints = luaL_checkudata(L, 1, HINTS_CLASS);
2012 
2013 	dns_hints_close(*hints);
2014 	*hints = 0;
2015 
2016 	return 0;
2017 } /* hints__gc() */
2018 
2019 
2020 static const luaL_Reg hints_methods[] = {
2021 	{ "insert", &hints_insert },
2022 	{ "grep",   &hints_grep },
2023 	{ NULL,     NULL },
2024 }; /* hints_methods[] */
2025 
2026 static const luaL_Reg hints_metatable[] = {
2027 	{ "__tostring", &hints__tostring },
2028 	{ "__gc",       &hints__gc },
2029 	{ NULL,         NULL }
2030 }; /* hints_metatable[] */
2031 
2032 static const luaL_Reg hints_globals[] = {
2033 	{ "new",       &hints_new },
2034 	{ "root",      &hints_root },
2035 	{ "stub",      &hints_stub },
2036 	{ "interpose", &hints_interpose },
2037 	{ "type",      &hints_type },
2038 	{ NULL,        NULL }
2039 };
2040 
luaopen__cqueues_dns_hints(lua_State * L)2041 int luaopen__cqueues_dns_hints(lua_State *L) {
2042 	cqs_newmetatable(L, HINTS_CLASS, hints_methods, hints_metatable, 0);
2043 
2044 	cqs_requiref(L, "_cqueues.dns.config", &luaopen__cqueues_dns_config, 0);
2045 	// not needed until dns_hints_query bound
2046 	//cqs_requiref(L, "_cqueues.dns.packet", &luaopen__cqueues_dns_packet, 0);
2047 
2048 	luaL_newlib(L, hints_globals);
2049 
2050 	return 1;
2051 } /* luaopen__cqueues_dns_hints() */
2052 
2053 
2054 /*
2055  * R E S O L V E R  B I N D I N G S
2056  *
2057  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2058 
2059 struct resolver {
2060 	struct dns_resolver *res;
2061 	lua_State *mainthread;
2062 }; /* struct resolver */
2063 
2064 
res_prep(lua_State * L)2065 static struct resolver *res_prep(lua_State *L) {
2066 	struct resolver *R = lua_newuserdata(L, sizeof *R);
2067 
2068 	R->res = 0;
2069 
2070 #if defined LUA_RIDX_MAINTHREAD
2071 	lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
2072 	R->mainthread = lua_tothread(L, -1);
2073 	lua_pop(L, 1);
2074 #else
2075 	R->mainthread = 0;
2076 #endif
2077 
2078 	luaL_setmetatable(L, RESOLVER_CLASS);
2079 
2080 	return R;
2081 } /* res_prep() */
2082 
2083 
res_closefd(int * fd,void * arg)2084 static int res_closefd(int *fd, void *arg) {
2085 	struct resolver *R = arg;
2086 
2087 	if (R->mainthread) {
2088 		cqs_cancelfd(R->mainthread, *fd);
2089 		cqs_closefd(fd);
2090 	}
2091 
2092 	return 0;
2093 } /* res_closefd() */
2094 
2095 
res_new(lua_State * L)2096 static int res_new(lua_State *L) {
2097 	struct resolver *R = res_prep(L);
2098 	struct dns_resolv_conf *resconf = resconf_test(L, 1);
2099 	struct dns_hosts *hosts = hosts_test(L, 2);
2100 	struct dns_hints *hints = hints_test(L, 3);
2101 	int error;
2102 
2103 	if (resconf)
2104 		dns_resconf_acquire(resconf);
2105 	if (hosts)
2106 		dns_hosts_acquire(hosts);
2107 	if (hints)
2108 		dns_hints_acquire(hints);
2109 
2110 	if (!resconf && !(resconf = dns_resconf_local(&error)))
2111 		goto error;
2112 
2113 	if (!hosts) {
2114 		if (resconf->options.recurse)
2115 			hosts = dns_hosts_open(&error);
2116 		else
2117 			hosts = dns_hosts_local(&error);
2118 
2119 		if (!hosts)
2120 			goto error;
2121 	}
2122 
2123 	if (!hints) {
2124 		if (resconf->options.recurse)
2125 			hints = dns_hints_root(resconf, &error);
2126 		else
2127 			hints = dns_hints_local(resconf, &error);
2128 
2129 		if (!hints)
2130 			goto error;
2131 	}
2132 
2133 	if (!(R->res = dns_res_open(resconf, hosts, hints, NULL, dns_opts(.closefd = { R, &res_closefd }), &error)))
2134 		goto error;
2135 
2136 	dns_resconf_close(resconf);
2137 	dns_hosts_close(hosts);
2138 	dns_hints_close(hints);
2139 
2140 	return 1;
2141 error:
2142 	dns_resconf_close(resconf);
2143 	dns_hosts_close(hosts);
2144 	dns_hints_close(hints);
2145 
2146 	lua_pushnil(L);
2147 	lua_pushinteger(L, error);
2148 
2149 	return 2;
2150 } /* res_new() */
2151 
2152 
res_interpose(lua_State * L)2153 static int res_interpose(lua_State *L) {
2154 	return cqs_interpose(L, RESOLVER_CLASS);
2155 } /* res_interpose() */
2156 
2157 
res_type(lua_State * L)2158 static int res_type(lua_State *L) {
2159 	struct resolver *R;
2160 
2161 	if ((R = luaL_testudata(L, 1, RESOLVER_CLASS))) {
2162 		lua_pushstring(L, (R->res)? "dns resolver" : "closed dns resolver");
2163 	} else {
2164 		lua_pushnil(L);
2165 	}
2166 
2167 	return 1;
2168 } /* res_type() */
2169 
2170 
res_check(lua_State * L,int index)2171 static inline struct dns_resolver *res_check(lua_State *L, int index) {
2172 	struct resolver *R = luaL_checkudata(L, index, RESOLVER_CLASS);
2173 
2174 	if (!R->res)
2175 		luaL_argerror(L, index, "resolver defunct");
2176 
2177 	return R->res;
2178 } /* res_check() */
2179 
2180 
res_submit(lua_State * L)2181 static int res_submit(lua_State *L) {
2182 	struct dns_resolver *R = res_check(L, 1);
2183 	const char *name = luaL_checkstring(L, 2);
2184 	int type = luaL_optint(L, 3, DNS_T_A);
2185 	int class = luaL_optint(L, 4, DNS_C_IN);
2186 	int error;
2187 
2188 	if (!(error = dns_res_submit(R, name, type, class))) {
2189 		lua_pushboolean(L, 1);
2190 
2191 		return 1;
2192 	} else {
2193 		lua_pushboolean(L, 0);
2194 		lua_pushinteger(L, error);
2195 
2196 		return 2;
2197 	}
2198 } /* res_submit() */
2199 
2200 
res_fetch(lua_State * L)2201 static int res_fetch(lua_State *L) {
2202 	struct dns_resolver *R = res_check(L, 1);
2203 	struct dns_packet *pkt;
2204 	size_t size;
2205 	int error;
2206 
2207 	if ((error = dns_res_check(R)) || !(pkt = dns_res_fetch(R, &error))) {
2208 error:
2209 		lua_pushboolean(L, 0);
2210 		lua_pushinteger(L, error);
2211 
2212 		return 2;
2213 	}
2214 
2215 	/* FIXME: Leaks packet if lua_newuserdata throws */
2216 	size = dns_p_sizeof(pkt);
2217 	error = dns_p_study(dns_p_copy(dns_p_init(lua_newuserdata(L, size), size), pkt));
2218 	free(pkt);
2219 
2220 	if (error)
2221 		goto error;
2222 
2223 	luaL_setmetatable(L, PACKET_CLASS);
2224 
2225 	return 1;
2226 } /* res_fetch() */
2227 
2228 
res_pollfd(lua_State * L)2229 static int res_pollfd(lua_State *L) {
2230 	struct dns_resolver *R = res_check(L, 1);
2231 
2232 	lua_pushinteger(L, dns_res_pollfd(R));
2233 
2234 	return 1;
2235 } /* res_pollfd() */
2236 
2237 
res_events(lua_State * L)2238 static int res_events(lua_State *L) {
2239 	struct dns_resolver *R = res_check(L, 1);
2240 
2241 	switch (dns_res_events(R)) {
2242 	case POLLIN|POLLOUT:
2243 		lua_pushliteral(L, "rw");
2244 		break;
2245 	case POLLIN:
2246 		lua_pushliteral(L, "r");
2247 		break;
2248 	case POLLOUT:
2249 		lua_pushliteral(L, "w");
2250 		break;
2251 	default:
2252 		lua_pushnil(L);
2253 		break;
2254 	}
2255 
2256 	return 1;
2257 } /* res_events() */
2258 
2259 
res_timeout(lua_State * L)2260 static int res_timeout(lua_State *L) {
2261 	struct dns_resolver *R = res_check(L, 1);
2262 
2263 	lua_pushnumber(L, dns_res_timeout(R));
2264 
2265 	return 1;
2266 } /* res_timeout() */
2267 
2268 
res_stat(lua_State * L)2269 static int res_stat(lua_State *L) {
2270 	struct dns_resolver *R = res_check(L, 1);
2271 	const struct dns_stat *st = dns_res_stat(R);
2272 
2273 	lua_newtable(L);
2274 
2275 	lua_pushinteger(L, st->queries);
2276 	lua_setfield(L, -2, "queries");
2277 
2278 #define setboth(st, table) do { \
2279 	lua_newtable(L); \
2280 	lua_pushinteger(L, (st).count); \
2281 	lua_setfield(L, -2, "count"); \
2282 	lua_pushinteger(L, (st).bytes); \
2283 	lua_setfield(L, -2, "bytes"); \
2284 	lua_setfield(L, -2, table); \
2285 } while (0)
2286 
2287 	lua_newtable(L);
2288 	setboth(st->udp.sent, "sent");
2289 	setboth(st->udp.rcvd, "rcvd");
2290 	lua_setfield(L, -2, "udp");
2291 
2292 	lua_newtable(L);
2293 	setboth(st->tcp.sent, "sent");
2294 	setboth(st->tcp.rcvd, "rcvd");
2295 	lua_setfield(L, -2, "tcp");
2296 
2297 #undef setboth
2298 
2299 	return 1;
2300 } /* res_stat() */
2301 
2302 
res_close(lua_State * L)2303 static int res_close(lua_State *L) {
2304 	struct resolver *R = luaL_checkudata(L, 1, RESOLVER_CLASS);
2305 
2306 	if (!R->mainthread) {
2307 		R->mainthread = L;
2308 		dns_res_close(R->res);
2309 		R->res = 0;
2310 		R->mainthread = 0;
2311 	} else {
2312 		dns_res_close(R->res);
2313 		R->res = 0;
2314 	}
2315 
2316 	return 0;
2317 } /* res_close() */
2318 
2319 
res__gc(lua_State * L)2320 static int res__gc(lua_State *L) {
2321 	struct resolver *R = luaL_checkudata(L, 1, RESOLVER_CLASS);
2322 
2323 	R->mainthread = 0;
2324 
2325 	dns_res_close(R->res);
2326 	R->res = 0;
2327 
2328 	return 0;
2329 } /* res__gc() */
2330 
2331 
2332 static const luaL_Reg res_methods[] = {
2333 	{ "submit",  &res_submit },
2334 	{ "fetch",   &res_fetch },
2335 	{ "pollfd",  &res_pollfd },
2336 	{ "events",  &res_events },
2337 	{ "timeout", &res_timeout },
2338 	{ "stat",    &res_stat },
2339 	{ "close",   &res_close },
2340 	{ NULL,      NULL },
2341 }; /* res_methods[] */
2342 
2343 static const luaL_Reg res_metatable[] = {
2344 	{ "__gc", &res__gc },
2345 	{ NULL,   NULL }
2346 }; /* res_metatable[] */
2347 
2348 static const luaL_Reg res_globals[] = {
2349 	{ "new",       &res_new },
2350 	{ "interpose", &res_interpose },
2351 	{ "type",      &res_type },
2352 	{ NULL,        NULL }
2353 };
2354 
luaopen__cqueues_dns_resolver(lua_State * L)2355 int luaopen__cqueues_dns_resolver(lua_State *L) {
2356 	cqs_newmetatable(L, RESOLVER_CLASS, res_methods, res_metatable, 0);
2357 
2358 	cqs_requiref(L, "_cqueues.dns.config", &luaopen__cqueues_dns_config, 0);
2359 	cqs_requiref(L, "_cqueues.dns.hosts", &luaopen__cqueues_dns_hosts, 0);
2360 	cqs_requiref(L, "_cqueues.dns.hints", &luaopen__cqueues_dns_hints, 0);
2361 	cqs_requiref(L, "_cqueues.dns.packet", &luaopen__cqueues_dns_packet, 0);
2362 
2363 	luaL_newlib(L, res_globals);
2364 
2365 	return 1;
2366 } /* luaopen__cqueues_dns_resolver() */
2367 
2368 
2369 /*
2370  * G L O B A L  B I N D I N G S
2371  *
2372  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2373 
dnsL_version(lua_State * L)2374 static int dnsL_version(lua_State *L) {
2375 	lua_pushinteger(L, dns_v_rel());
2376 	lua_pushinteger(L, dns_v_abi());
2377 	lua_pushinteger(L, dns_v_api());
2378 
2379 	return 3;
2380 } /* dnsL_version() */
2381 
2382 
dnsL_random(lua_State * L)2383 static int dnsL_random(lua_State *L) {
2384 	lua_Number modn = luaL_optnumber(L, 1, UINT_MAX + 1.0);
2385 
2386 	if (modn >= (UINT_MAX + 1.0)) {
2387 		lua_pushnumber(L, dns_random());
2388 	} else {
2389 		unsigned n = (unsigned)modn;
2390 		unsigned r, min;
2391 
2392 		luaL_argcheck(L, n > 1, 1, lua_pushfstring(L, "[0, %d): interval is empty", (int)n));
2393 
2394 		min = -n % n;
2395 
2396 		for (;;) {
2397 			r = dns_random();
2398 
2399 			if (r >= min)
2400 				break;
2401 		}
2402 
2403 		lua_pushinteger(L, r % n);
2404 	}
2405 
2406 	return 1;
2407 } /* dnsL_random() */
2408 
2409 
2410 static const luaL_Reg dnsL_globals[] = {
2411 	{ "version", &dnsL_version },
2412 	{ "random",  &dnsL_random },
2413 	{ NULL,      NULL }
2414 };
2415 
luaopen__cqueues_dns(lua_State * L)2416 int luaopen__cqueues_dns(lua_State *L) {
2417 	luaL_newlib(L, dnsL_globals);
2418 
2419 	return 1;
2420 } /* luaopen__cqueues_dns() */
2421 
2422 
2423