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