summaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2014-12-10 03:05:47 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2014-12-10 03:05:47 +0000
commit416ef5e2bf59bb2e45066a1d5d91ac677c0f48e5 (patch)
tree1c746d673dcec7a8488c6ac51db8245411034376 /src/include
downloads6-dns-416ef5e2bf59bb2e45066a1d5d91ac677c0f48e5.tar.xz
Initial commit
Diffstat (limited to 'src/include')
-rw-r--r--src/include/s6-dns/s6dns-analyze.h39
-rw-r--r--src/include/s6-dns/s6dns-constants.h52
-rw-r--r--src/include/s6-dns/s6dns-debug.h16
-rw-r--r--src/include/s6-dns/s6dns-domain.h47
-rw-r--r--src/include/s6-dns/s6dns-engine.h108
-rw-r--r--src/include/s6-dns/s6dns-fmt.h29
-rw-r--r--src/include/s6-dns/s6dns-ip46.h29
-rw-r--r--src/include/s6-dns/s6dns-message.h175
-rw-r--r--src/include/s6-dns/s6dns-rci.h29
-rw-r--r--src/include/s6-dns/s6dns-resolve.h242
-rw-r--r--src/include/s6-dns/s6dns.h18
-rw-r--r--src/include/s6-dns/skadns.h73
12 files changed, 857 insertions, 0 deletions
diff --git a/src/include/s6-dns/s6dns-analyze.h b/src/include/s6-dns/s6dns-analyze.h
new file mode 100644
index 0000000..2908763
--- /dev/null
+++ b/src/include/s6-dns/s6dns-analyze.h
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#ifndef S6DNS_ANALYZE_H
+#define S6DNS_ANALYZE_H
+
+#include <skalibs/uint16.h>
+#include <skalibs/genwrite.h>
+#include <s6-dns/s6dns-message.h>
+
+typedef int s6dns_analyze_record_func_t (genwrite_t *, s6dns_message_rr_t const *, char const *, unsigned int, unsigned int) ;
+typedef s6dns_analyze_record_func_t *s6dns_analyze_record_func_t_ref ;
+
+typedef struct s6dns_analyze_rtypetable_s s6dns_analyze_rtypetable_t, *s6dns_analyze_rtypetable_t_ref ;
+struct s6dns_analyze_rtypetable_s
+{
+ uint16 rtype ;
+ char const *string ;
+ s6dns_analyze_record_func_t_ref f ;
+} ;
+
+extern uint16 s6dns_analyze_qtype_parse (char const *) ;
+
+extern s6dns_analyze_rtypetable_t const *s6dns_analyze_rtypetable ;
+
+extern s6dns_analyze_record_func_t s6dns_analyze_record_a ;
+extern s6dns_analyze_record_func_t s6dns_analyze_record_aaaa ;
+extern s6dns_analyze_record_func_t s6dns_analyze_record_hinfo ;
+extern s6dns_analyze_record_func_t s6dns_analyze_record_soa ;
+extern s6dns_analyze_record_func_t s6dns_analyze_record_mx ;
+extern s6dns_analyze_record_func_t s6dns_analyze_record_srv ;
+extern s6dns_analyze_record_func_t s6dns_analyze_record_domain ;
+extern s6dns_analyze_record_func_t s6dns_analyze_record_strings ;
+extern s6dns_analyze_record_func_t s6dns_analyze_record_unknown ;
+
+extern s6dns_analyze_record_func_t s6dns_analyze_record ;
+
+extern int s6dns_analyze_packet (genwrite_t *, char const *, unsigned int, int) ;
+
+#endif
diff --git a/src/include/s6-dns/s6dns-constants.h b/src/include/s6-dns/s6dns-constants.h
new file mode 100644
index 0000000..ad47dc1
--- /dev/null
+++ b/src/include/s6-dns/s6dns-constants.h
@@ -0,0 +1,52 @@
+/* ISC license. */
+
+#ifndef S6DNS_CONSTANTS_H
+#define S6DNS_CONSTANTS_H
+
+#include <skalibs/ip46.h>
+
+#define S6DNS_MAX_SERVERS 16U
+
+#define S6DNS_C_IN 0x0001U
+#define S6DNS_C_ANY 0x00ffU
+
+#define S6DNS_T_A 1U
+#define S6DNS_T_NS 2U
+#define S6DNS_T_CNAME 5U
+#define S6DNS_T_SOA 6U
+#define S6DNS_T_PTR 12U
+#define S6DNS_T_HINFO 13U
+#define S6DNS_T_MX 15U
+#define S6DNS_T_TXT 16U
+#define S6DNS_T_RP 17U
+#define S6DNS_T_SIG 24U
+#define S6DNS_T_KEY 25U
+#define S6DNS_T_AAAA 28U
+#define S6DNS_T_SRV 33U
+#define S6DNS_T_AXFR 252U
+#define S6DNS_T_ANY 255U
+
+#define S6DNS_O_RECURSIVE 0x0001U
+#define S6DNS_O_STRICT 0x0002U
+
+#define S6DNS_W_AND 0
+#define S6DNS_W_OR 1
+#define S6DNS_W_BEST 2
+
+typedef struct s6dns_constants_error_message_s s6dns_constants_error_message_t, *s6dns_constants_error_message_t_ref ;
+struct s6dns_constants_error_message_s
+{
+ int num ;
+ char const *string ;
+} ;
+
+extern s6dns_constants_error_message_t const *const s6dns_constants_error ;
+extern char const *s6dns_constants_error_str (int) ;
+
+#ifdef SKALIBS_IPV6_ENABLED
+# define S6DNS_LOCALHOST_IP IP6_LOCAL
+#else
+# define S6DNS_LOCALHOST_IP "\177\0\0\1"
+#endif
+
+#endif
diff --git a/src/include/s6-dns/s6dns-debug.h b/src/include/s6-dns/s6dns-debug.h
new file mode 100644
index 0000000..acc5818
--- /dev/null
+++ b/src/include/s6-dns/s6dns-debug.h
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#ifndef S6DNS_DEBUG_H
+#define S6DNS_DEBUG_H
+
+#include <s6-dns/s6dns-engine.h>
+
+extern s6dns_debughook_func_t s6dns_debug_dumpdt_post_recv ;
+extern s6dns_debughook_func_t s6dns_debug_dumpdt_pre_send ;
+extern s6dns_debughook_func_t s6dns_debug_dumpdt_post_send ;
+
+#define S6DNS_DEBUG_DUMPDT_INIT(gp) { &s6dns_debug_dumpdt_post_recv, &s6dns_debug_dumpdt_pre_send, &s6dns_debug_dumpdt_post_send, (gp) }
+extern s6dns_debughook_t const s6dns_debug_dumpdt_stdout ;
+extern s6dns_debughook_t const s6dns_debug_dumpdt_stderr ;
+
+#endif
diff --git a/src/include/s6-dns/s6dns-domain.h b/src/include/s6-dns/s6dns-domain.h
new file mode 100644
index 0000000..3faae07
--- /dev/null
+++ b/src/include/s6-dns/s6dns-domain.h
@@ -0,0 +1,47 @@
+/* ISC license. */
+
+#ifndef S6DNS_DOMAIN_H
+#define S6DNS_DOMAIN_H
+
+#include <skalibs/ip46.h>
+
+typedef struct s6dns_domain_s s6dns_domain_t, *s6dns_domain_t_ref ;
+struct s6dns_domain_s
+{
+ unsigned char len ;
+ char s[255] ;
+} ;
+
+
+ /* Conversions from/to user strings */
+
+extern int s6dns_domain_fromstring (s6dns_domain_t_ref, char const *, unsigned int) ;
+extern unsigned int s6dns_domain_tostring (char *, unsigned int, s6dns_domain_t const *) ;
+
+
+ /* Qualification */
+
+extern int s6dns_domain_noqualify (s6dns_domain_t_ref) ;
+extern unsigned int s6dns_domain_qualify (s6dns_domain_t *, s6dns_domain_t const *, char const *, unsigned int) ;
+
+
+ /* Internal coding/encoding to/from protocol form */
+
+extern int s6dns_domain_encode (s6dns_domain_t_ref) ;
+extern unsigned int s6dns_domain_encodelist (s6dns_domain_t_ref, unsigned int) ;
+extern int s6dns_domain_decode (s6dns_domain_t_ref) ;
+
+
+ /* Useful shortcuts */
+
+extern int s6dns_domain_fromstring_noqualify_encode (s6dns_domain_t_ref, char const *, unsigned int) ;
+extern unsigned int s6dns_domain_fromstring_qualify_encode (s6dns_domain_t *, char const *, unsigned int, char const *, unsigned int) ;
+
+
+ /* Helpers for PTR */
+
+extern void s6dns_domain_arpafromip4 (s6dns_domain_t_ref, char const *) ;
+extern void s6dns_domain_arpafromip6 (s6dns_domain_t_ref, char const *, unsigned int) ;
+#define s6dns_domain_arpafromip46(d, i) (ip46_is6(i) ? s6dns_domain_arpafromip6(d, (i)->ip, 128) : s6dns_domain_arpafromip4(d, (i)->ip))
+
+#endif
diff --git a/src/include/s6-dns/s6dns-engine.h b/src/include/s6-dns/s6dns-engine.h
new file mode 100644
index 0000000..d6b0503
--- /dev/null
+++ b/src/include/s6-dns/s6dns-engine.h
@@ -0,0 +1,108 @@
+/* ISC license. */
+
+#ifndef S6DNS_ENGINE_H
+#define S6DNS_ENGINE_H
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+#include <skalibs/stralloc.h>
+#include <s6-dns/s6dns-constants.h>
+#include <s6-dns/s6dns-ip46.h>
+
+
+ /* The dt structure: all the DNS q/r state information, transport-agnostic */
+
+typedef struct s6dns_engine_s s6dns_engine_t, *s6dns_engine_t_ref ;
+
+
+ /* Debug function hooks */
+
+typedef int s6dns_debughook_func_t (s6dns_engine_t const *, void *) ;
+typedef s6dns_debughook_func_t *s6dns_debughook_func_t_ref ;
+
+typedef struct s6dns_debughook_s s6dns_debughook_t, *s6dns_debughook_t_ref ;
+struct s6dns_debughook_s
+{
+ s6dns_debughook_func_t_ref post_recv ;
+ s6dns_debughook_func_t_ref pre_send ;
+ s6dns_debughook_func_t_ref post_send ;
+ void *external ;
+} ;
+#define S6DNS_DEBUGHOOK_ZERO { 0, 0, 0, 0 }
+extern s6dns_debughook_t const s6dns_debughook_zero ;
+
+
+ /*
+ s6dns-engine: the asynchronous DNS resolution primitives.
+ */
+
+struct s6dns_engine_s
+{
+ stralloc sa ; /* 2 bytes (qlen) + qlen bytes (query) + answers */
+ tain_t deadline ;
+ tain_t localdeadline ;
+ unsigned int querylen ;
+ int fd ;
+ uint32 protostate ;
+ s6dns_ip46list_t servers ;
+ s6dns_debughook_t const *debughook ;
+ unsigned int curserver ;
+ int status ;
+ unsigned int flagstrict : 1 ;
+ unsigned int flagtcp : 1 ;
+ unsigned int flagconnecting : 1 ;
+ unsigned int flagreading : 1 ;
+ unsigned int flagwriting : 1 ;
+} ;
+
+#define S6DNS_ENGINE_ZERO { \
+ .sa = STRALLOC_ZERO, \
+ .deadline = TAIN_ZERO, \
+ .localdeadline = TAIN_ZERO, \
+ .querylen = 0, \
+ .fd = -1, \
+ .protostate = 0, \
+ .servers = S6DNS_IP46LIST_ZERO, \
+ .debughook = 0, \
+ .curserver = 0, \
+ .status = ECONNABORTED, \
+ .flagstrict = 0, \
+ .flagtcp = 0, \
+ .flagconnecting = 0, \
+ .flagreading = 0, \
+ .flagwriting = 0 \
+}
+
+extern s6dns_engine_t const s6dns_engine_zero ;
+extern s6dns_engine_t s6dns_engine_here ;
+
+extern void s6dns_engine_recycle (s6dns_engine_t *) ;
+extern void s6dns_engine_free (s6dns_engine_t *) ;
+extern void s6dns_engine_freen (s6dns_engine_t *, unsigned int) ;
+
+#define s6dns_engine_init(dt, servers, options, q, qlen, qtype, deadline, stamp) s6dns_engine_init_r(dt, servers, options, q, qlen, qtype, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_engine_init_g(dt, servers, options, q, qlen, qtype, deadline) s6dns_engine_init(dt, servers, options, q, qlen, qtype, (deadline), &STAMP)
+extern int s6dns_engine_init_r (s6dns_engine_t *, s6dns_ip46list_t const *, uint32, char const *, unsigned int, uint16, s6dns_debughook_t const *, tain_t const *, tain_t const *) ;
+#define s6dns_engine_init_r_g(dt, servers, options, q, qlen, qtype, dbh, deadline) s6dns_engine_init_r(dt, servers, options, q, qlen, qtype, dbh, (deadline), &STAMP)
+
+
+ /* Call before iopause() */
+
+extern void s6dns_engine_nextdeadline (s6dns_engine_t const *, tain_t *) ;
+#define s6dns_engine_isreadable(dt) ((dt)->flagreading)
+#define s6dns_engine_iswritable(dt) ((dt)->flagwriting)
+
+
+ /* Call after iopause(): _timeout if iopause returns 0, _event otherwise */
+
+extern int s6dns_engine_timeout (s6dns_engine_t *, tain_t const *) ;
+#define s6dns_engine_timeout_g(dt) s6dns_engine_timeout((dt), &STAMP)
+extern int s6dns_engine_event (s6dns_engine_t *, tain_t const *) ;
+#define s6dns_engine_event_g(dt) s6dns_engine_event((dt), &STAMP)
+
+#define s6dns_engine_packet(dt) ((dt)->sa.s + (dt)->querylen)
+#define s6dns_engine_packetlen(dt) ((dt)->sa.len - (dt)->querylen)
+
+#endif
diff --git a/src/include/s6-dns/s6dns-fmt.h b/src/include/s6-dns/s6dns-fmt.h
new file mode 100644
index 0000000..fd4dfc5
--- /dev/null
+++ b/src/include/s6-dns/s6dns-fmt.h
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#ifndef S6DNS_FMT_H
+#define S6DNS_FMT_H
+
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <s6-dns/s6dns-domain.h>
+#include <s6-dns/s6dns-message.h>
+
+#define S6DNS_FMT_DOMAIN 256
+#define s6dns_fmt_domain(s, max, d) s6dns_domain_tostring(s, max, d)
+
+#define S6DNS_FMT_DOMAINLIST(n) ((n) * S6DNS_FMT_DOMAIN)
+extern unsigned int s6dns_fmt_domainlist (char *, unsigned int, s6dns_domain_t const *, unsigned int, char const *, unsigned int) ;
+
+#define S6DNS_FMT_HINFO 512
+extern unsigned int s6dns_fmt_hinfo (char *, unsigned int, s6dns_message_rr_hinfo_t const *) ;
+
+#define S6DNS_FMT_MX (S6DNS_FMT_DOMAIN + UINT16_FMT)
+extern unsigned int s6dns_fmt_mx (char *, unsigned int, s6dns_message_rr_mx_t const *) ;
+
+#define S6DNS_FMT_SOA (S6DNS_FMT_DOMAIN * 2 + 5 * UINT32_FMT)
+extern unsigned int s6dns_fmt_soa (char *, unsigned int, s6dns_message_rr_soa_t const *) ;
+
+#define S6DNS_FMT_SRV (S6DNS_FMT_DOMAIN + 3 * UINT16_FMT)
+extern unsigned int s6dns_fmt_srv (char *, unsigned int, s6dns_message_rr_srv_t const *) ;
+
+#endif
diff --git a/src/include/s6-dns/s6dns-ip46.h b/src/include/s6-dns/s6dns-ip46.h
new file mode 100644
index 0000000..d09aa7f
--- /dev/null
+++ b/src/include/s6-dns/s6dns-ip46.h
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#ifndef S6DNS_IP46_H
+#define S6DNS_IP46_H
+
+#include <skalibs/bitarray.h>
+#include <skalibs/ip46.h>
+#include <s6-dns/s6dns-constants.h>
+
+typedef struct s6dns_ip46list_s s6dns_ip46list_t, *s6dns_ip46list_t_ref ;
+struct s6dns_ip46list_s
+{
+ char ip[S6DNS_MAX_SERVERS * SKALIBS_IP_SIZE] ;
+#ifdef SKALIBS_IPV6_ENABLED
+ unsigned char is6[bitarray_div8(S6DNS_MAX_SERVERS)] ;
+#endif
+} ;
+
+#define s6dns_ip46list_ip(list, i) ((list)->ip + SKALIBS_IP_SIZE * (i))
+
+#ifdef SKALIBS_IPV6_ENABLED
+# define S6DNS_IP46LIST_ZERO { .ip = S6DNS_LOCALHOST_IP, .is6 = "\0" }
+# define s6dns_ip46list_is6(list, i) bitarray_peek((list)->is6, i)
+#else
+# define S6DNS_IP46LIST_ZERO { .ip = S6DNS_LOCALHOST_IP }
+# define s6dns_ip46list_is6(list, i) 0
+#endif
+
+#endif
diff --git a/src/include/s6-dns/s6dns-message.h b/src/include/s6-dns/s6dns-message.h
new file mode 100644
index 0000000..d26106b
--- /dev/null
+++ b/src/include/s6-dns/s6dns-message.h
@@ -0,0 +1,175 @@
+/* ISC license. */
+
+#ifndef S6DNS_MESSAGE_H
+#define S6DNS_MESSAGE_H
+
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <s6-dns/s6dns-domain.h>
+
+
+ /* Header */
+
+typedef struct s6dns_message_counts_s s6dns_message_counts_t, *s6dns_message_counts_t_ref ;
+struct s6dns_message_counts_s
+{
+ uint16 qd ;
+ uint16 an ;
+ uint16 ns ;
+ uint16 nr ;
+} ;
+
+#define S6DNS_MESSAGE_COUNTS_ZERO { .qd = 0, .an = 0, .ns = 0, .nr = 0 }
+extern s6dns_message_counts_t const s6dns_message_counts_zero ;
+
+extern void s6dns_message_counts_pack (char *, s6dns_message_counts_t const *) ;
+extern void s6dns_message_counts_unpack (char const *, s6dns_message_counts_t *) ;
+extern unsigned int s6dns_message_counts_next (s6dns_message_counts_t *) ;
+
+typedef struct s6dns_message_header_s s6dns_message_header_t, *s6dns_message_header_t_ref ;
+struct s6dns_message_header_s
+{
+ uint16 id ;
+ unsigned int qr : 1 ;
+ unsigned int opcode : 4 ;
+ unsigned int aa : 1 ;
+ unsigned int tc : 1 ;
+ unsigned int rd : 1 ;
+ unsigned int ra : 1 ;
+ unsigned int z : 3 ;
+ unsigned int rcode : 4 ;
+ s6dns_message_counts_t counts ;
+} ;
+
+#define S6DNS_MESSAGE_HEADER_ZERO { \
+ .id = 0, \
+ .qr = 0, \
+ .opcode = 0, \
+ .aa = 0, \
+ .tc = 0, \
+ .rd = 0, \
+ .ra = 0, \
+ .z = 0, \
+ .rcode = 0, \
+ .counts = S6DNS_MESSAGE_COUNTS_ZERO \
+}
+extern s6dns_message_header_t const s6dns_message_header_zero ;
+
+extern void s6dns_message_header_pack (char *, s6dns_message_header_t const *) ;
+extern void s6dns_message_header_unpack (char const *, s6dns_message_header_t *) ;
+
+
+ /* Specific RR helpers */
+
+extern int s6dns_message_get_string (s6dns_domain_t *, char const *, unsigned int, unsigned int *) ;
+extern int s6dns_message_get_strings (char *, unsigned int, char const *, unsigned int, unsigned int *) ;
+extern int s6dns_message_get_domain (s6dns_domain_t *, char const *, unsigned int, unsigned int *) ;
+
+typedef struct s6dns_message_rr_hinfo_s s6dns_message_rr_hinfo_t, *s6dns_message_rr_hinfo_t_ref ;
+struct s6dns_message_rr_hinfo_s
+{
+ s6dns_domain_t cpu ;
+ s6dns_domain_t os ;
+} ;
+
+extern int s6dns_message_get_hinfo (s6dns_message_rr_hinfo_t *, char const *, unsigned int, unsigned int *) ;
+
+typedef struct s6dns_message_rr_mx_s s6dns_message_rr_mx_t, *s6dns_message_rr_mx_t_ref ;
+struct s6dns_message_rr_mx_s
+{
+ uint16 preference ;
+ s6dns_domain_t exchange ;
+} ;
+
+extern int s6dns_message_get_mx (s6dns_message_rr_mx_t *, char const *, unsigned int, unsigned int *) ;
+
+typedef struct s6dns_message_rr_soa_s s6dns_message_rr_soa_t, *s6dns_message_rr_soa_t_ref ;
+struct s6dns_message_rr_soa_s
+{
+ s6dns_domain_t mname ;
+ s6dns_domain_t rname ;
+ uint32 serial ;
+ uint32 refresh ;
+ uint32 retry ;
+ uint32 expire ;
+ uint32 minimum ;
+} ;
+
+extern int s6dns_message_get_soa (s6dns_message_rr_soa_t *, char const *, unsigned int, unsigned int *) ;
+
+typedef struct s6dns_message_rr_srv_s s6dns_message_rr_srv_t, *s6dns_message_rr_srv_t_ref ;
+struct s6dns_message_rr_srv_s
+{
+ uint16 priority ;
+ uint16 weight ;
+ uint16 port ;
+ s6dns_domain_t target ;
+} ;
+
+extern int s6dns_message_get_srv (s6dns_message_rr_srv_t *, char const *, unsigned int, unsigned int *) ;
+
+
+ /* The callback function type: how to parse RRs */
+
+typedef struct s6dns_message_rr_s s6dns_message_rr_t, *s6dns_message_rr_t_ref ;
+struct s6dns_message_rr_s
+{
+ s6dns_domain_t name ;
+ uint16 rtype ;
+ uint16 rclass ;
+ uint32 ttl ;
+ uint16 rdlength ;
+} ;
+
+typedef int s6dns_message_rr_func_t (s6dns_message_rr_t const *, char const *, unsigned int, unsigned int, unsigned int, void *) ;
+typedef s6dns_message_rr_func_t *s6dns_message_rr_func_t_ref ;
+
+
+ /* mpag: structure to encode several variable-length results */
+
+typedef struct s6dns_mpag_s s6dns_mpag_t, *s6dns_mpag_t_ref ;
+struct s6dns_mpag_s
+{
+ stralloc sa ;
+ genalloc offsets ; /* array of unsigned int */
+ uint16 rtype ;
+} ;
+#define S6DNS_MPAG_ZERO { .sa = STRALLOC_ZERO, .offsets = GENALLOC_ZERO, .rtype = 0 }
+
+
+ /* dpag: structure for domain lists */
+
+typedef struct s6dns_dpag_s s6dns_dpag_t, *s6dns_dpag_t_ref ;
+struct s6dns_dpag_s
+{
+ genalloc ds ; /* array of s6dns_domain_t */
+ uint16 rtype ;
+} ;
+#define S6DNS_DPAG_ZERO { .ds = GENALLOC_ZERO, .rtype = 0 }
+
+
+extern s6dns_message_rr_func_t s6dns_message_parse_answer_strings ;
+extern s6dns_message_rr_func_t s6dns_message_parse_answer_domain ;
+extern s6dns_message_rr_func_t s6dns_message_parse_answer_a ;
+extern s6dns_message_rr_func_t s6dns_message_parse_answer_aaaa ;
+extern s6dns_message_rr_func_t s6dns_message_parse_answer_mx ;
+extern s6dns_message_rr_func_t s6dns_message_parse_answer_hinfo ;
+extern s6dns_message_rr_func_t s6dns_message_parse_answer_soa ;
+extern s6dns_message_rr_func_t s6dns_message_parse_answer_srv ;
+
+
+ /* The actual parsing function */
+
+extern int s6dns_message_parse (s6dns_message_header_t_ref, char const *, unsigned int, s6dns_message_rr_func_t_ref, void *) ;
+
+
+ /* Internals of this function, for lower level access */
+
+extern int s6dns_message_parse_init (s6dns_message_header_t *, s6dns_message_counts_t_ref, char const *, unsigned int, unsigned int *) ;
+extern unsigned int s6dns_message_parse_skipqd (s6dns_message_counts_t *, char const *, unsigned int, unsigned int *) ;
+extern int s6dns_message_parse_getrr (s6dns_message_rr_t_ref, char const *, unsigned int, unsigned int *) ;
+extern unsigned int s6dns_message_parse_next (s6dns_message_counts_t *, s6dns_message_rr_t const *, char const *, unsigned int, unsigned int *) ;
+
+#endif
diff --git a/src/include/s6-dns/s6dns-rci.h b/src/include/s6-dns/s6dns-rci.h
new file mode 100644
index 0000000..5822a71
--- /dev/null
+++ b/src/include/s6-dns/s6dns-rci.h
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#ifndef S6DNS_RCI_H
+#define S6DNS_RCI_H
+
+#include <skalibs/stralloc.h>
+#include <skalibs/s6dns-constants.h>
+#include <skalibs/s6dns-ip46.h>
+#include <skalibs/s6dns-domain.h>
+
+ /* rci: resolv.conf information */
+
+typedef struct s6dns_rci_s s6dns_rci_t, *s6dns_rci_t_ref ;
+struct s6dns_rci_s
+{
+ s6dns_ip46list_t servers ;
+ stralloc rules ;
+ unsigned int rulesnum ;
+} ;
+#define S6DNS_RCI_ZERO { .servers = S6DNS_IP46LIST_ZERO, .rules = STRALLOC_ZERO, .rulesnum = 0 }
+
+extern s6dns_rci_t const s6dns_rci_zero ;
+extern s6dns_rci_t s6dns_rci_here ;
+extern int s6dns_rci_init (s6dns_rci_t_ref, char const *) ;
+extern void s6dns_rci_free (s6dns_rci_t_ref) ;
+
+#define s6dns_qualify(list, d) s6dns_domain_qualify(list, (d), s6dns_rci_here.rules.s, s6dns_rci_here.rulesnum)
+
+#endif
diff --git a/src/include/s6-dns/s6dns-resolve.h b/src/include/s6-dns/s6dns-resolve.h
new file mode 100644
index 0000000..d188a67
--- /dev/null
+++ b/src/include/s6-dns/s6dns-resolve.h
@@ -0,0 +1,242 @@
+ /* ISC license. */
+
+#ifndef S6DNS_RESOLVE_H
+#define S6DNS_RESOLVE_H
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/ip46.h>
+#include <skalibs/s6dns-constants.h>
+#include <skalibs/s6dns-ip46.h>
+#include <skalibs/s6dns-domain.h>
+#include <skalibs/s6dns-message.h>
+#include <skalibs/s6dns-engine.h>
+#include <skalibs/s6dns-rci.h>
+
+ /*
+ Synchronous DNS resolution primitives.
+ The non-reentrant functions are just wrappers around the reentrant ones,
+ using globals for the parameters the user doesn't care about:
+ s6dns_engine_here for the query storage (dt),
+ s6dns_debughook_zero meaning no debugging needed,
+ s6dns_rci_here for the resolv.conf information (qualification rules and
+ initial cache IPs)
+ */
+
+ /*
+ The basic s6dns_engine wrapper loop: takes an initted dt and resolves it.
+ */
+
+#define s6dns_resolve_loop(deadline, stamp) s6dns_resolve_loop_r(&s6dns_engine_here, (deadline), stamp)
+#define s6dns_resolve_loop_g(deadline) s6dns_resolve_loop((deadline), &STAMP)
+#define s6dns_resolve_loop_r(dt, deadline, stamp) (s6dns_resolven_loop(dt, 1, 2, deadline, stamp) < 0 ? 0 : (dt)->status ? (errno = (dt)->status, 0) : 1)
+#define s6dns_resolve_loop_r_g(dt, deadline) s6dns_resolve_loop(dt, (deadline), &STAMP)
+
+
+ /* QoL functions for single-domain synchronous resolution. */
+
+ /*
+ The innermost one:
+ Initializes the dt with the given data (d, qtype), then calls the loop.
+ */
+
+#define s6dns_resolve_core(d, qtype, deadline, stamp) s6dns_resolve_core_r(d, qtype, &s6dns_engine_here, &s6dns_rci_here.servers, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_core_g(d, qtype, deadline) s6dns_resolve_core(d, qtype, (deadline), &STAMP)
+extern int s6dns_resolve_core_r (s6dns_domain_t const *, uint16, s6dns_engine_t_ref, s6dns_ip46list_t const *, s6dns_debughook_t const *, tain_t const *, tain_t *) ;
+#define s6dns_resolve_core_r_g(d, qtype, dt, servers, dbh, deadline) s6dns_resolve_core_r(d, qtype, dt, servers, dbh, (deadline), &STAMP)
+
+
+ /*
+ Just above. Calls s6dns_resolve_core() then feeds the result to s6dns_message_parse().
+ Returns -1 if a resolving or parsing error occurs.
+ Returns 0 if everything works but the result is empty for some reason (i.e. nxdomain).
+ Returns 1 if everything works and there's an actual answer.
+ */
+
+#define s6dns_resolve_parse(d, qtype, parsefunc, parsedata, deadline, stamp) s6dns_resolve_parse_r(d, qtype, parsefunc, parsedata, &s6dns_engine_here, &s6dns_rci_here.servers, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_parse_g(d, qtype, parsefunc, parsedata, deadline) s6dns_resolve_parse(d, qtype, parsefunc, parsedata, (deadline), &STAMP)
+extern int s6dns_resolve_parse_r (s6dns_domain_t const *, uint16, s6dns_message_rr_func_t_ref, void *, s6dns_engine_t_ref, s6dns_ip46list_t const *, s6dns_debughook_t const *, tain_t const *, tain_t *) ;
+#define s6dns_resolve_parse_r_g(d, qtype, parsefunc, parsedata, dt, servers, dbh, deadline) s6dns_resolve_parse_r(d, qtype, parsefunc, parsedata, dt, servers, dbh, (deadline), &STAMP)
+
+
+ /*
+ Resolution without qualification. Encoding/decoding included.
+ */
+
+#define s6dns_resolvenoq(name, len, qtype, parsefunc, parsedata, deadline, stamp) s6dns_resolvenoq_r(name, len, qtype, parsefunc, parsedata, &s6dns_engine_here, &s6dns_rci_here.servers, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolvenoq_g(name, len, qtype, parsefunc, parsedata, deadline) s6dns_resolvenoq(name, len, qtype, parsefunc, parsedata, (deadline), &STAMP)
+extern int s6dns_resolvenoq_r (char const *, unsigned int, uint16, s6dns_message_rr_func_t_ref, void *, s6dns_engine_t_ref, s6dns_ip46list_t const *, s6dns_debughook_t const *, tain_t const *, tain_t *) ;
+#define s6dns_resolvenoq_r_g(name, len, qtype, parsefunc, parsedata, dt, servers, dbh, deadline) s6dns_resolvenoq_r(name, len, qtype, parsefunc, parsedata, dt, servers, dbh, (deadline), &STAMP)
+
+
+ /*
+ Resolution with qualification:
+ Get a qualification list from a name, then resolve the list in parallel.
+ */
+
+#define s6dns_resolveq(name, len, qtype, parsefunc, parsedata, deadline, stamp) s6dns_resolveq_r(name, len, qtype, parsefunc, parsedata, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolveq_g(name, len, qtype, parsefunc, parsedata, deadline) s6dns_resolveq(name, len, qtype, parsefunc, parsedata, (deadline), &STAMP)
+extern int s6dns_resolveq_r (char const *, unsigned int, uint16, s6dns_message_rr_func_t_ref, void *, s6dns_rci_t const *, s6dns_debughook_t const *, tain_t const *, tain_t *) ;
+#define s6dns_resolveq_r_g(name, len, qtype, parsefunc, parsedata, rci, dbh, deadline) s6dns_resolveq_r(name, len, qtype, parsefunc, parsedata, rci, dbh, (deadline), &STAMP)
+
+
+ /*
+ The resolution primitive that calls s6dns_resolvenoq() if the
+ qualif flag is cleared and s6dns_resolveq() if it is set.
+ */
+
+#define s6dns_resolve(name, len, qtype, parsefunc, parsedata, qualif, deadline, stamp) s6dns_resolve_r(name, len, qtype, parsefunc, parsedata, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_t const *, deadline, stamp)
+#define s6dns_resolve_g(name, len, qtype, parsefunc, parsedata, qualif, deadline) s6dns_resolve(name, len, qtype, parsefunc, parsedata, qualif, (deadline), &STAMP)
+#define s6dns_resolve_r(name, len, qtype, parsefunc, parsedata, qualif, dt, rci, dbh, deadline, stamp) ((qualif) ? s6dns_resolveq_r(name, len, qtype, parsefunc, parsedata, rci, dbh, deadline, stamp) : s6dns_resolvenoq_r(name, len, qtype, parsefunc, parsedata, dt, &(rci)->servers, dbh, deadline, stamp))
+#define s6dns_resolve_r_g(name, len, qtype, parsefunc, parsedata, qualif, dt, rci, dbh, deadline) s6dns_resolve_r(name, len, qtype, parsefunc, parsedata, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+
+ /* How to perform both AAAA and A queries at the same time */
+
+#define s6dns_resolvenoq_aaaaa(ips, name, len, deadline, stamp) s6dns_resolvenoq_aaaaa_r(ips, name, len, &s6dns_rci_here.servers, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolvenoq_aaaaa_g(ips, name, len, deadline) s6dns_resolvenoq_aaaaa(ips, name, len, (deadline), &STAMP)
+extern int s6dns_resolvenoq_aaaaa_r(genalloc *, char const *, unsigned int, s6dns_ip46list_t const *, s6dns_debughook_t const *, tain_t const *, tain_t *) ;
+#define s6dns_resolvenoq_aaaaa_r_g(ips, name, len, servers, dbh, deadline) s6dns_resolvenoq_aaaaa_r(ips, name, len, servers, dbh, (deadline), &STAMP)
+
+#define s6dns_resolveq_aaaaa(ips, name, len, deadline, stamp) s6dns_resolveq_aaaaa_r(ips, name, len, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolveq_aaaaa_g(ips, name, len, deadline) s6dns_resolveq_aaaaa(ips, name, len, (deadline), &STAMP)
+extern int s6dns_resolveq_aaaaa_r(genalloc *, char const *, unsigned int, s6dns_rci_t const *, s6dns_debughook_t const *, tain_t const *, tain_t *) ;
+#define s6dns_resolveq_aaaaa_r_g(ips, name, len, rci, dbh, deadline) s6dns_resolvenoq_aaaaa_r(ips, name, len, rci, dbh, (deadline), &STAMP)
+
+
+ /*
+ Some high-level functions.
+ Queries are automatically translated to domain form and encoded.
+ Domains returned in a stralloc are automatically decoded.
+ Warning: decoded domains all start with '.'
+ The int flag decides if qualification is needed or not.
+ */
+
+ /*
+ For A fields: the stralloc answer has 4 chars per IP4.
+ For AAAA fields: the stralloc answer has 16 chars per IP6.
+ For TXT fields (and other mpag stuff): the stralloc contains the strings
+ and the genalloc contains a list of offsets into that stralloc.
+ For other fields: the result is stored in a genalloc of the appropriate type.
+ */
+
+#define s6dns_resolve_a(ips, name, len, qualif, deadline, stamp) s6dns_resolve_a_r(ips, name, len, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_a_g(ips, name, len, qualif, deadline) s6dns_resolve_a(ips, name, len, qualif, (deadline), &STAMP)
+#define s6dns_resolve_a_r(ips, name, len, qualif, dt, rci, dbh, deadline, stamp) s6dns_resolve_r(name, len, S6DNS_T_A, &s6dns_message_parse_answer_a, (ips), qualif, dt, rci, dbh, deadline, stamp)
+#define s6dns_resolve_a_r_g(ips, name, len, qualif, dt, rci, dbh, deadline) s6dns_resolve_a_r(ips, name, len, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_aaaa(ip6s, name, len, qualif, deadline, stamp) s6dns_resolve_aaaa_r(ip6s, name, len, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_aaaa_g(ip6s, name, len, qualif, deadline) s6dns_resolve_aaaa(ip6s, name, len, qualif, (deadline), &STAMP)
+#define s6dns_resolve_aaaa_r(ip6s, name, len, qualif, dt, rci, dbh, deadline, stamp) s6dns_resolve_r(name, len, S6DNS_T_AAAA, &s6dns_message_parse_answer_aaaa, (ip6s), qualif, dt, rci, dbh, deadline, stamp)
+#define s6dns_resolve_aaaa_r_g(ip6s, name, len, qualif, dt, rci, dbh, deadline) s6dns_resolve_aaaa_r(ip6s, name, len, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_aaaaa(ips, name, len, qualif, deadline, stamp) s6dns_resolve_aaaaa_r(ips, name, len, qualif, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_aaaaa_g(ips, name, len, qualif, deadline) s6dns_resolve_aaaaa(ips, name, len, qualif, (deadline), &STAMP)
+#define s6dns_resolve_aaaaa_r(ips, name, len, qualif, rci, dbh, deadline, stamp) ((qualif) ? s6dns_resolveq_aaaaa_r(ips, name, len, rci, dbh, deadline, stamp) : s6dns_resolvenoq_aaaaa_r(ips, name, len, &(rci)->servers, dbh, deadline, stamp))
+#define s6dns_resolve_aaaaa_r_g(ips, name, len, qualif, rci, dbh, deadline) s6dns_resolve_aaaaa_r(ips, name, len, qualif, rci, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_ptr(ds, name, len, deadline, stamp) s6dns_resolve_ptr_r(ds, name, len, &s6dns_engine_here, &s6dns_rci_here.servers, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_ptr_g(ds, name, len, deadline) s6dns_resolve_ptr(ds, name, len, (deadline), &STAMP)
+#define s6dns_resolve_ptr_r(ds, name, len, dt, servers, dbh, deadline, stamp) s6dns_resolvenoq_r(name, len, S6DNS_T_PTR, &s6dns_message_parse_answer_domain, (ds), dt, servers, dbh, deadline, stamp)
+#define s6dns_resolve_ptr_r_g(ds, name, len, dt, servers, dbh, deadline) s6dns_resolve_ptr_r(ds, name, len, dt, servers, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_name4(ds, ip, deadline, stamp) s6dns_resolve_name4_r(ds, ip, &s6dns_engine_here, &s6dns_rci_here.servers, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_name4_g(ds, ip, deadline) s6dns_resolve_name4(ds, ip, (deadline), &STAMP)
+extern int s6dns_resolve_name4_r (genalloc *, char const *, s6dns_engine_t_ref, s6dns_ip46list_t const *, s6dns_debughook_t const *, tain_t const *, tain_t *) ;
+#define s6dns_resolve_name4_r_g(ds, ip, dt, servers, dbh, deadline) s6dns_resolve_name4_r(ds, ip, dt, servers, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_name6(ds, ip6, deadline, stamp) s6dns_resolve_name6_r(ds, ip6, &s6dns_engine_here, &s6dns_rci_here.servers, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_name6_g(ds, ip6, deadline) s6dns_resolve_name6(ds, ip6, (deadline), &STAMP)
+extern int s6dns_resolve_name6_r (genalloc *, char const *, s6dns_engine_t_ref, s6dns_ip46list_t const *, s6dns_debughook_t const *, tain_t const *, tain_t *) ;
+#define s6dns_resolve_name6_r_g(ds, ip6, dt, servers, dbh, deadline) s6dns_resolve_name6_r(ds, ip6, dt, servers, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_name46(ds, i, deadline, stamp) s6dns_resolve_name46_r(ds, i, &s6dns_engine_here, &s6dns_rci_here.servers, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_name46_g(ds, i, deadline) s6dns_resolve_name46(ds, i, (deadline), &STAMP)
+#define s6dns_resolve_name46_r(ds, i, dt, servers, dbh, deadline, stamp) (ip46_is6(i) ? s6dns_resolve_name6_r(ds, (i)->ip, dt, servers, dbh, deadline, stamp) : s6dns_resolve_name4_r(ds, (i)->ip, dt, servers, dbh, deadline, stamp))
+#define s6dns_resolve_name46_r_g(ds, i, dt, servers, dbh, deadline) s6dns_resolve_name46_r(ds, i, dt, servers, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_txt(sa, offsets, name, len, qualif, deadline, stamp) s6dns_resolve_txt_r(sa, offsets, name, len, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_txt_g(sa, offsets, name, len, qualif, deadline) s6dns_resolve_txt(sa, offsets, name, len, qualif, (deadline), &STAMP)
+#define s6dns_resolve_txt_r(sa, offsets, name, len, qualif, dt, rci, dbh, deadline, stamp) s6dns_resolve_mpag_r(sa, offsets, name, len, S6DNS_T_TXT, &s6dns_message_parse_answer_strings, qualif, dt, rci, dbh, deadline, stamp)
+#define s6dns_resolve_txt_r_g(sa, offsets, name, len, qualif, dt, rci, dbh, deadline) s6dns_resolve_txt_r(sa, offsets, name, len, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_mx(mxs, name, len, qualif, deadline, stamp) s6dns_resolve_mx_r(mxs, name, len, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_mx_g(mxs, name, len, qualif, deadline) s6dns_resolve_mx(mxs, name, len, qualif, (deadline), &STAMP)
+#define s6dns_resolve_mx_r(mxs, name, len, qualif, dt, rci, dbh, deadline, stamp) s6dns_resolve_r(name, len, S6DNS_T_MX, &s6dns_message_parse_answer_mx, (mxs), qualif, dt, rci, dbh, deadline, stamp)
+#define s6dns_resolve_mx_r_g(mxs, name, len, qualif, dt, rci, dbh, deadline) s6dns_resolve_mx_r(mxs, name, len, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_ns(ds, name, len, qualif, deadline, stamp) s6dns_resolve_ns_r(ds, name, len, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_ns_g(ds, name, len, qualif, deadline) s6dns_resolve_ns(ds, name, len, qualif, (deadline), &STAMP)
+#define s6dns_resolve_ns_r(ds, name, len, qualif, dt, rci, dbh, deadline, stamp) s6dns_resolve_dpag_r(ds, name, len, S6DNS_T_NS, qualif, dt, rci, dbh, deadline, stamp)
+#define s6dns_resolve_ns_r_g(ds, name, len, qualif, dt, rci, dbh, deadline) s6dns_resolve_ns_r(ds, name, len, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_cname(ds, name, len, qualif, deadline, stamp) s6dns_resolve_cname_r(ds, name, len, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_cname_g(ds, name, len, qualif, deadline) s6dns_resolve_cname(ds, name, len, qualif, (deadline), &STAMP)
+#define s6dns_resolve_cname_r(ds, name, len, qualif, dt, rci, dbh, deadline, stamp) s6dns_resolve_dpag_r(ds, name, len, S6DNS_T_CNAME, qualif, dt, rci, dbh, deadline, stamp)
+#define s6dns_resolve_cname_r_g(ds, name, len, qualif, dt, rci, dbh, deadline) s6dns_resolve_cname_r(ds, name, len, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_hinfo(hinfos, name, len, qualif, deadline, stamp) s6dns_resolve_hinfo_r(hinfos, name, len, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_hinfo_g(hinfos, name, len, qualif, deadline) s6dns_resolve_hinfo(hinfos, name, len, qualif, (deadline), &STAMP)
+#define s6dns_resolve_hinfo_r(hinfos, name, len, qualif, dt, rci, dbh, deadline, stamp) s6dns_resolve_r(name, len, S6DNS_T_HINFO, &s6dns_message_parse_answer_hinfo, (hinfos), qualif, dt, rci, dbh, deadline, stamp)
+#define s6dns_resolve_hinfo_r_g(hinfos, name, len, qualif, dt, rci, dbh, deadline) s6dns_resolve_hinfo_r(hinfos, name, len, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_srv(srvs, name, len, qualif, deadline, stamp) s6dns_resolve_srv_r(srvs, name, len, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_srv_g(srvs, name, len, qualif, deadline) s6dns_resolve_srv(srvs, name, len, qualif, (deadline), &STAMP)
+#define s6dns_resolve_srv_r(srvs, name, len, qualif, dt, rci, dbh, deadline, stamp) s6dns_resolve_r(name, len, S6DNS_T_SRV, &s6dns_message_parse_answer_srv, (srvs), qualif, dt, rci, dbh, deadline, stamp)
+#define s6dns_resolve_srv_r_g(srvs, name, len, qualif, dt, rci, dbh, deadline) s6dns_resolve_srv_r(srvs, name, len, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_soa(soas, name, len, qualif, deadline, stamp) s6dns_resolve_soa_r(soas, name, len, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_soa_g(soas, name, len, qualif, deadline) s6dns_resolve_soa(soas, name, len, qualif, (deadline), &STAMP)
+#define s6dns_resolve_soa_r(soas, name, len, qualif, dt, rci, dbh, deadline, stamp) s6dns_resolve_r(name, len, S6DNS_T_SOA, &s6dns_message_parse_answer_soa, (soas), qualif, dt, rci, dbh, deadline, stamp)
+#define s6dns_resolve_soa_r_g(soas, name, len, qualif, dt, rci, dbh, deadline) s6dns_resolve_soa_r(soas, name, len, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+
+ /* Internals for the high-level functions. */
+
+ /* dpag: structure for generic domain lists + rtype */
+ /* mpag: encoding variable-length information into storage+offsets */
+
+#define s6dns_resolve_dpag(ds, name, len, qtype, qualif, deadline, stamp) s6dns_resolve_dpag_r(ds, name, len, qtype, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_dpag_g(ds, name, len, qtype, qualif, deadline) s6dns_resolve_dpag(ds, name, len, qtype, qualif, (deadline), &STAMP)
+extern int s6dns_resolve_dpag_r (genalloc *, char const *, unsigned int, uint16, int, s6dns_engine_t_ref, s6dns_rci_t const *, s6dns_debughook_t const *, tain_t const *, tain_t *) ;
+#define s6dns_resolve_dpag_r_g(ds, name, len, qtype, qualif, dt, rci, dbh, deadline) s6dns_resolve_dpag_r(ds, name, len, qtype, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+#define s6dns_resolve_mpag(sa, offsets, name, len, qtype, parsefunc, qualif, deadline, stamp) s6dns_resolve_mpag_r(sa, offsets, name, len, qtype, parsefunc, qualif, &s6dns_engine_here, &s6dns_rci_here, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolve_mpag_g(sa, offsets, name, len, qtype, parsefunc, qualif, deadline) s6dns_resolve_mpag(sa, offsets, name, len, qtype, parsefunc, qualif, (deadline), &STAMP)
+extern int s6dns_resolve_mpag_r (stralloc *, genalloc *, char const *, unsigned int, uint16, s6dns_message_rr_func_t_ref, int, s6dns_engine_t_ref, s6dns_rci_t const *, s6dns_debughook_t const *, tain_t const *, tain_t *) ;
+#define s6dns_resolve_mpag_r_g(sa, offsets, name, len, qtype, parsefunc, qualif, dt, rci, dbh, deadline) s6dns_resolve_mpag_r(sa, offsets, name, len, qtype, parsefunc, qualif, dt, rci, dbh, (deadline), &STAMP)
+
+
+ /*
+ Functions for n-domain parallel resolution.
+ s6dns_resolven_loop() is the core primitive.
+ s6dns_resolven_parse() is built upon it.
+ This API is still very limited in what it can do; for full
+ asynchronous resolution, use the skadns library.
+ */
+
+extern int s6dns_resolven_loop (s6dns_engine_t_ref, unsigned int, unsigned int, tain_t const *, tain_t *) ;
+#define s6dns_resolven_loop_g(list, n, or, deadline) s6dns_resolven(list, n, or, (deadline), &STAMP)
+
+typedef struct s6dns_resolve_s s6dns_resolve_t, *s6dns_resolve_t_ref ;
+struct s6dns_resolve_s
+{
+ s6dns_domain_t q ;
+ tain_t deadline ;
+ s6dns_message_rr_func_t_ref parsefunc ;
+ void *data ;
+ uint32 options ;
+ int status ;
+ uint16 qtype ;
+} ;
+
+#define s6dns_resolven_parse(list, n, deadline, stamp) s6dns_resolven_parse_r(list, n, &s6dns_rci_here.servers, &s6dns_debughook_zero, deadline, stamp)
+#define s6dns_resolven_parse_g(list, n, deadline) s6dns_resolven_parse(list, n, (deadline), &STAMP)
+extern int s6dns_resolven_parse_r (s6dns_resolve_t_ref, unsigned int, s6dns_ip46list_t const *, s6dns_debughook_t const *, tain_t const *, tain_t *) ;
+#define s6dns_resolven_parse_r_g(list, n, servers, dbh, deadline) s6dns_resolven_parse_r(list, n, servers, dbh, (deadline), &STAMP)
+
+#endif
diff --git a/src/include/s6-dns/s6dns.h b/src/include/s6-dns/s6dns.h
new file mode 100644
index 0000000..dbc1138
--- /dev/null
+++ b/src/include/s6-dns/s6dns.h
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#ifndef S6DNS_H
+#define S6DNS_H
+
+#include <s6-dns/s6dns-constants.h>
+#include <s6-dns/s6dns-ip46.h>
+#include <s6-dns/s6dns-domain.h>
+#include <s6-dns/s6dns-message.h>
+#include <s6-dns/s6dns-engine.h>
+#include <s6-dns/s6dns-rci.h>
+#include <s6-dns/s6dns-resolve.h>
+#include <s6-dns/s6dns-fmt.h>
+
+#define s6dns_init() s6dns_rci_init(&s6dns_rci_here, "/etc/resolv.conf")
+#define s6dns_finish() (s6dns_engine_free(&s6dns_engine_here), s6dns_rci_free(&s6dns_rci_here))
+
+#endif
diff --git a/src/include/s6-dns/skadns.h b/src/include/s6-dns/skadns.h
new file mode 100644
index 0000000..d5ed82f
--- /dev/null
+++ b/src/include/s6-dns/skadns.h
@@ -0,0 +1,73 @@
+/* ISC license. */
+
+#ifndef SKADNS_H
+#define SKADNS_H
+
+#include <errno.h>
+#include <skalibs/config.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/skaclient.h>
+#include <s6-dns/config.h>
+#include <s6-dns/s6dns-domain.h>
+
+#define SKADNSD_PROG S6_DNS_BINPREFIX "skadnsd"
+#define SKADNS_BANNER1 "skadns v1.0 (b)\n"
+#define SKADNS_BANNER1_LEN (sizeof SKADNS_BANNER1 - 1)
+#define SKADNS_BANNER2 "skadns v1.0 (a)\n"
+#define SKADNS_BANNER2_LEN (sizeof SKADNS_BANNER2 - 1)
+#define SKADNS_MAXCONCURRENCY 1000
+
+typedef struct skadnsanswer_s skadnsanswer_t, *skadnsanswer_t_ref ;
+struct skadnsanswer_s
+{
+ int status ;
+ char *data ;
+ unsigned int len ;
+} ;
+#define SKADNSANSWER_ZERO { .status = EINVAL, .data = 0, .len = 0 }
+
+typedef struct skadns_s skadns_t, *skadns_t_ref ;
+struct skadns_s
+{
+ skaclient_t connection ;
+ genalloc list ; /* array of uint16 */
+ gensetdyn q ; /* set of skadnsanswer_t */
+ skaclient_buffer_t buffers ;
+} ;
+#define SKADNS_ZERO { .connection = SKACLIENT_ZERO, .list = GENALLOC_ZERO, .q = GENSETDYN_INIT(skadnsanswer_t, 3, 3, 8) }
+extern skadns_t const skadns_zero ;
+
+
+ /* Starting and ending a session */
+
+extern int skadns_start (skadns_t *, char const *, tain_t const *, tain_t *) ;
+#define skadns_start_g(a, path, deadline) skadns_start(a, path, (deadline), &STAMP)
+extern int skadns_startf (skadns_t *, tain_t const *, tain_t *) ;
+#define skadns_startf_g(a, deadline) skadns_startf(a, (deadline), &STAMP)
+extern void skadns_end (skadns_t *) ;
+
+
+ /* Synchronous functions */
+
+extern int skadns_send (skadns_t *, uint16 *, s6dns_domain_t const *, uint16, tain_t const *, tain_t const *, tain_t *) ;
+#define skadns_send_g(a, id, d, qtype, limit, deadline) skadns_send(a, id, d, qtype, limit, (deadline), &STAMP)
+extern int skadns_cancel (skadns_t *, uint16, tain_t const *, tain_t *) ;
+#define skadns_cancel_g(a, id, deadline) skadns_cancel(a, id, (deadline), &STAMP)
+
+
+ /* Asynchronous functions */
+
+#define skadns_fd(a) skaclient_fd(&(a)->connection)
+extern int skadns_update (skadns_t *) ;
+#define skadns_list(a) genalloc_s(uint16 const, &(a)->list)
+#define skadns_clearlist(a) ((a)->list.len = 0)
+extern int skadns_packetlen (skadns_t const *, uint16) ;
+extern char const *skadns_packet (skadns_t const *, uint16) ;
+extern int skadns_release (skadns_t *, uint16) ;
+
+#endif