diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2014-12-10 03:05:47 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2014-12-10 03:05:47 +0000 |
commit | 416ef5e2bf59bb2e45066a1d5d91ac677c0f48e5 (patch) | |
tree | 1c746d673dcec7a8488c6ac51db8245411034376 /src | |
download | s6-dns-416ef5e2bf59bb2e45066a1d5d91ac677c0f48e5.tar.xz |
Initial commit
Diffstat (limited to 'src')
149 files changed, 5235 insertions, 0 deletions
diff --git a/src/clients/deps-exe/s6-dnsip4 b/src/clients/deps-exe/s6-dnsip4 new file mode 100644 index 0000000..4181fd6 --- /dev/null +++ b/src/clients/deps-exe/s6-dnsip4 @@ -0,0 +1,4 @@ +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnsip4-filter b/src/clients/deps-exe/s6-dnsip4-filter new file mode 100644 index 0000000..2c61392 --- /dev/null +++ b/src/clients/deps-exe/s6-dnsip4-filter @@ -0,0 +1,6 @@ +libs6dnsgenericfilter.a +-lskadns +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnsip6 b/src/clients/deps-exe/s6-dnsip6 new file mode 100644 index 0000000..4181fd6 --- /dev/null +++ b/src/clients/deps-exe/s6-dnsip6 @@ -0,0 +1,4 @@ +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnsip6-filter b/src/clients/deps-exe/s6-dnsip6-filter new file mode 100644 index 0000000..2c61392 --- /dev/null +++ b/src/clients/deps-exe/s6-dnsip6-filter @@ -0,0 +1,6 @@ +libs6dnsgenericfilter.a +-lskadns +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnsmx b/src/clients/deps-exe/s6-dnsmx new file mode 100644 index 0000000..4181fd6 --- /dev/null +++ b/src/clients/deps-exe/s6-dnsmx @@ -0,0 +1,4 @@ +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnsname b/src/clients/deps-exe/s6-dnsname new file mode 100644 index 0000000..4181fd6 --- /dev/null +++ b/src/clients/deps-exe/s6-dnsname @@ -0,0 +1,4 @@ +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnsname-filter b/src/clients/deps-exe/s6-dnsname-filter new file mode 100644 index 0000000..2c61392 --- /dev/null +++ b/src/clients/deps-exe/s6-dnsname-filter @@ -0,0 +1,6 @@ +libs6dnsgenericfilter.a +-lskadns +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnsns b/src/clients/deps-exe/s6-dnsns new file mode 100644 index 0000000..4181fd6 --- /dev/null +++ b/src/clients/deps-exe/s6-dnsns @@ -0,0 +1,4 @@ +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnsq b/src/clients/deps-exe/s6-dnsq new file mode 100644 index 0000000..4181fd6 --- /dev/null +++ b/src/clients/deps-exe/s6-dnsq @@ -0,0 +1,4 @@ +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnsqr b/src/clients/deps-exe/s6-dnsqr new file mode 100644 index 0000000..4181fd6 --- /dev/null +++ b/src/clients/deps-exe/s6-dnsqr @@ -0,0 +1,4 @@ +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnsqualify b/src/clients/deps-exe/s6-dnsqualify new file mode 100644 index 0000000..295d71e --- /dev/null +++ b/src/clients/deps-exe/s6-dnsqualify @@ -0,0 +1,2 @@ +-ls6dns +-lskarnet diff --git a/src/clients/deps-exe/s6-dnssoa b/src/clients/deps-exe/s6-dnssoa new file mode 100644 index 0000000..4181fd6 --- /dev/null +++ b/src/clients/deps-exe/s6-dnssoa @@ -0,0 +1,4 @@ +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnssrv b/src/clients/deps-exe/s6-dnssrv new file mode 100644 index 0000000..4181fd6 --- /dev/null +++ b/src/clients/deps-exe/s6-dnssrv @@ -0,0 +1,4 @@ +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-dnstxt b/src/clients/deps-exe/s6-dnstxt new file mode 100644 index 0000000..4181fd6 --- /dev/null +++ b/src/clients/deps-exe/s6-dnstxt @@ -0,0 +1,4 @@ +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-exe/s6-randomip b/src/clients/deps-exe/s6-randomip new file mode 100644 index 0000000..e027835 --- /dev/null +++ b/src/clients/deps-exe/s6-randomip @@ -0,0 +1,3 @@ +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/clients/deps-lib/s6dnsgenericfilter b/src/clients/deps-lib/s6dnsgenericfilter new file mode 100644 index 0000000..2d5eee8 --- /dev/null +++ b/src/clients/deps-lib/s6dnsgenericfilter @@ -0,0 +1,2 @@ +s6dns_generic_filter_main.o +s6dns_namescanner.o diff --git a/src/clients/s6-dnsip4-filter.c b/src/clients/s6-dnsip4-filter.c new file mode 100644 index 0000000..6d6862e --- /dev/null +++ b/src/clients/s6-dnsip4-filter.c @@ -0,0 +1,52 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/fmtscan.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-message.h> +#include "s6dns-generic-filter.h" + +#define USAGE "s6-dnsip4-filter [ -l lines ] [ -c concurrency ] [ -t timeout ] [ -f format ] [ -e errorformat ]" + +typedef struct s6dns_a1_s s6dns_a1_t, *s6dns_a1_t_ref ; +struct s6dns_a1_s +{ + char ip[4] ; + unsigned int got : 1 ; +} ; + +static int s6dns_message_parse_answer_a1 (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *stuff) +{ + if ((section == 2) && (rr->rtype == S6DNS_T_A) && (rr->rdlength == 4)) + { + s6dns_a1_t *data = stuff ; + if (data->got) return 1 ; + byte_copy(data->ip, 4, packet+pos) ; + data->got = 1 ; + } + (void)packetlen ; + return 1 ; +} + +static int ipformatter (stralloc *sa, char const *packet, unsigned int packetlen) +{ + s6dns_a1_t data ; + s6dns_message_header_t h ; + register int r ; + data.got = 0 ; + r = s6dns_message_parse(&h, packet, packetlen, &s6dns_message_parse_answer_a1, &data) ; + if (r <= 0) return r ; + if (!data.got) return 1 ; + if (!stralloc_readyplus(sa, IP4_FMT)) return -1 ; + sa->len += ip4_fmt(sa->s + sa->len, data.ip) ; + stralloc_0(sa) ; + return 1 ; +} + +int main (int argc, char const *const *argv, char const *const *envp) +{ + PROG = "s6-dnsip4-filter" ; + return s6dns_generic_filter_main(argc, argv, envp, S6DNS_T_A, &s6dns_namescanner, &ipformatter, USAGE) ; +} diff --git a/src/clients/s6-dnsip4.c b/src/clients/s6-dnsip4.c new file mode 100644 index 0000000..03c52dd --- /dev/null +++ b/src/clients/s6-dnsip4.c @@ -0,0 +1,62 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint.h> +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/tai.h> +#include <skalibs/random.h> +#include <s6-dns/s6dns.h> + +#define USAGE "s6-dnsip4 [ -q ] [ -r ] [ -t timeout ] domain" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + stralloc ips = STRALLOC_ZERO ; + tain_t deadline ; + unsigned int i = 0 ; + int flagqualify = 0 ; + int flagunsort = 0 ; + PROG = "s6-dnsip4" ; + + for (;;) + { + register int opt = subgetopt(argc, argv, "qrt:") ; + if (opt == -1) break ; + switch (opt) + { + case 'q' : flagqualify = 1 ; break ; + case 'r' : flagunsort = 1 ; break ; + case 't' : if (!uint0_scan(subgetopt_here.arg, &i)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= subgetopt_here.ind ; argv += subgetopt_here.ind ; + if (argc < 1) dieusage() ; + + tain_now_g() ; + if (i) tain_from_millisecs(&deadline, i) ; else deadline = tain_infinite_relative ; + tain_add_g(&deadline, &deadline) ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + { + register int r = s6dns_resolve_a_g(&ips, argv[0], str_len(argv[0]), flagqualify, &deadline) ; + if (r < 0) strerr_diefu2sys((errno == ETIMEDOUT) ? 99 : 111, "resolve ", argv[0]) ; + if (!r) strerr_diefu4x(2, "resolve ", argv[0], ": ", s6dns_constants_error_str(errno)) ; + } + if (!ips.len) return 1 ; + if (flagunsort) random_unsort(ips.s, ips.len / 4, 4) ; + for (i = 0 ; i < ips.len / 4 ; i++) + { + char fmt[IP4_FMT] ; + register unsigned int n = ip4_fmt(fmt, ips.s + 4 * i) ; + fmt[n++] = '\n' ; + if (buffer_put(buffer_1small, fmt, n) < (int)n) + strerr_diefu1sys(111, "write to stdout") ; + } + if (!buffer_flush(buffer_1small)) + strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/clients/s6-dnsip6-filter.c b/src/clients/s6-dnsip6-filter.c new file mode 100644 index 0000000..a5c7418 --- /dev/null +++ b/src/clients/s6-dnsip6-filter.c @@ -0,0 +1,52 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/fmtscan.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-message.h> +#include "s6dns-generic-filter.h" + +#define USAGE "s6-dnsip6-filter [ -l lines ] [ -c concurrency ] [ -t timeout ] [ -f format ] [ -e errorformat ]" + +typedef struct s6dns_aaaa1_s s6dns_aaaa1_t, *s6dns_aaaa1_t_ref ; +struct s6dns_aaaa1_s +{ + char ip[16] ; + unsigned int got : 1 ; +} ; + +static int s6dns_message_parse_answer_aaaa1 (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *stuff) +{ + if ((section == 2) && (rr->rtype == S6DNS_T_AAAA) && (rr->rdlength == 16)) + { + s6dns_aaaa1_t *data = stuff ; + if (data->got) return 1 ; + byte_copy(data->ip, 16, packet+pos) ; + data->got = 1 ; + } + (void)packetlen ; + return 1 ; +} + +static int ipformatter (stralloc *sa, char const *packet, unsigned int packetlen) +{ + s6dns_aaaa1_t data ; + s6dns_message_header_t h ; + register int r ; + data.got = 0 ; + r = s6dns_message_parse(&h, packet, packetlen, &s6dns_message_parse_answer_aaaa1, &data) ; + if (r <= 0) return r ; + if (!data.got) return 1 ; + if (!stralloc_readyplus(sa, IP6_FMT)) return -1 ; + sa->len += ip6_fmt(sa->s + sa->len, data.ip) ; + stralloc_0(sa) ; + return 1 ; +} + +int main (int argc, char const *const *argv, char const *const *envp) +{ + PROG = "s6-dnsip6-filter" ; + return s6dns_generic_filter_main(argc, argv, envp, S6DNS_T_AAAA, &s6dns_namescanner, &ipformatter, USAGE) ; +} diff --git a/src/clients/s6-dnsip6.c b/src/clients/s6-dnsip6.c new file mode 100644 index 0000000..e07ba53 --- /dev/null +++ b/src/clients/s6-dnsip6.c @@ -0,0 +1,62 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint.h> +#include <skalibs/sgetopt.h> +#include <skalibs/bytestr.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/tai.h> +#include <skalibs/random.h> +#include <s6-dns/s6dns.h> + +#define USAGE "s6-dnsip6 [ -q ] [ -r ] [ -t timeout ] domain" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + stralloc ips = STRALLOC_ZERO ; + tain_t deadline ; + unsigned int i = 0 ; + int flagqualify = 0 ; + int flagunsort = 0 ; + PROG = "s6-dnsip6" ; + + for (;;) + { + register int opt = subgetopt(argc, argv, "qrt:") ; + if (opt == -1) break ; + switch (opt) + { + case 'q' : flagqualify = 1 ; break ; + case 'r' : flagunsort = 1 ; break ; + case 't' : if (!uint0_scan(subgetopt_here.arg, &i)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= subgetopt_here.ind ; argv += subgetopt_here.ind ; + if (argc < 1) dieusage() ; + + tain_now_g() ; + if (i) tain_from_millisecs(&deadline, i) ; else deadline = tain_infinite_relative ; + tain_add_g(&deadline, &deadline) ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + { + register int r = s6dns_resolve_aaaa_g(&ips, argv[0], str_len(argv[0]), flagqualify, &deadline) ; + if (r < 0) strerr_diefu2sys((errno == ETIMEDOUT) ? 99 : 111, "resolve ", argv[0]) ; + if (!r) strerr_diefu4x(2, "resolve ", argv[0], ": ", s6dns_constants_error_str(errno)) ; + } + if (!ips.len) return 1 ; + if (flagunsort) random_unsort(ips.s, ips.len / 16, 16) ; + for (i = 0 ; i < ips.len / 16 ; i++) + { + char fmt[IP6_FMT] ; + register unsigned int n = ip6_fmt(fmt, ips.s + 16 * i) ; + fmt[n++] = '\n' ; + if (buffer_put(buffer_1small, fmt, n) < (int)n) + strerr_diefu1sys(111, "write to stdout") ; + } + if (!buffer_flush(buffer_1small)) + strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/clients/s6-dnsmx.c b/src/clients/s6-dnsmx.c new file mode 100644 index 0000000..a495cb2 --- /dev/null +++ b/src/clients/s6-dnsmx.c @@ -0,0 +1,64 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/tai.h> +#include <skalibs/genalloc.h> +#include <skalibs/random.h> +#include <s6-dns/s6dns.h> + +#define USAGE "s6-dnsmx [ -q ] [ -r ] [ -t timeout ] name" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + genalloc mxs = GENALLOC_ZERO ; /* array of s6dns_message_rr_mx_t */ + tain_t deadline ; + unsigned int i = 0 ; + int flagqualify = 0 ; + int flagunsort = 0 ; + PROG = "s6-dnsmx" ; + for (;;) + { + register int opt = subgetopt(argc, argv, "qrt:") ; + if (opt == -1) break ; + switch (opt) + { + case 'q' : flagqualify = 1 ; break ; + case 'r' : flagunsort = 1 ; break ; + case 't' : if (!uint0_scan(subgetopt_here.arg, &i)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= subgetopt_here.ind ; argv += subgetopt_here.ind ; + if (argc < 1) dieusage() ; + + tain_now_g() ; + if (i) tain_from_millisecs(&deadline, i) ; else deadline = tain_infinite_relative ; + tain_add_g(&deadline, &deadline) ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + { + register int r = s6dns_resolve_mx_g(&mxs, argv[0], str_len(argv[0]), flagqualify, &deadline) ; + if (r < 0) strerr_diefu2sys((errno == ETIMEDOUT) ? 99 : 111, "resolve ", argv[0]) ; + if (!r) strerr_diefu4x(2, "resolve ", argv[0], ": ", s6dns_constants_error_str(errno)) ; + } + if (!genalloc_len(s6dns_message_rr_mx_t, &mxs)) return 1 ; + if (flagunsort) random_unsort(mxs.s, genalloc_len(s6dns_message_rr_mx_t, &mxs), sizeof(s6dns_message_rr_mx_t)) ; + for (i = 0 ; i < genalloc_len(s6dns_message_rr_mx_t, &mxs) ; i++) + { + char buf[S6DNS_FMT_MX] ; + register unsigned int len = s6dns_fmt_mx(buf, S6DNS_FMT_MX, genalloc_s(s6dns_message_rr_mx_t, &mxs) + i) ; + if (!len) strerr_diefu1sys(111, "format result") ; + if (buffer_put(buffer_1, buf, len) < 0) goto err ; + if (buffer_put(buffer_1, "\n", 1) < 0) goto err ; + } + if (!buffer_flush(buffer_1)) goto err ; + return 0 ; + err: + strerr_diefu1sys(111, "write to stdout") ; +} diff --git a/src/clients/s6-dnsname-filter.c b/src/clients/s6-dnsname-filter.c new file mode 100644 index 0000000..6522003 --- /dev/null +++ b/src/clients/s6-dnsname-filter.c @@ -0,0 +1,83 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/strerr2.h> +#include <skalibs/fmtscan.h> +#include <skalibs/stralloc.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-message.h> +#include "s6dns-generic-filter.h" + +#define USAGE "s6-dnsname-filter [ -4 ] [ -6 ] [ -l lines ] [ -c concurrency ] [ -t timeout ] [ -f format ] [ -e errorformat ]" + +static unsigned int ipscanner (s6dns_domain_t_ref d, char const *s) +{ + char ip[16] ; + register unsigned int pos ; + if (flag6) + { + pos = ip6_scan(s, ip) ; + if (pos) + { + s6dns_domain_arpafromip6(d, ip, 128) ; + goto yes ; + } + } + if (flag4) + { + pos = ip4_scan(s, ip) ; + if (pos) + { + s6dns_domain_arpafromip4(d, ip) ; + goto yes ; + } + } + return 0 ; + yes: + if (!s6dns_domain_encode(d)) return 0 ; + return pos ; +} + +typedef struct s6dns_domain1_s s6dns_domain1_t, *s6dns_domain1_t_ref ; +struct s6dns_domain1_s +{ + s6dns_domain_t d ; + unsigned int got : 1 ; +} ; + +static int s6dns_message_parse_answer_domain1 (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *stuff) +{ + if ((section == 2) && (rr->rtype == S6DNS_T_PTR)) + { + s6dns_domain1_t *data = stuff ; + register unsigned int start = pos ; + if (data->got) return 1 ; + if (!s6dns_message_get_domain(&data->d, packet, packetlen, &pos)) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + data->got = 1 ; + } + return 1 ; +} + +static int domainformatter (stralloc *sa, char const *packet, unsigned int packetlen) +{ + s6dns_domain1_t data ; + s6dns_message_header_t h ; + register int r ; + data.got = 0 ; + r = s6dns_message_parse(&h, packet, packetlen, &s6dns_message_parse_answer_domain1, &data) ; + if (r <= 0) return r ; + if (!data.got) return 1 ; + if (!stralloc_readyplus(sa, data.d.len + 1)) return -1 ; + sa->len += s6dns_domain_tostring(sa->s + sa->len, data.d.len + 1, &data.d) ; + stralloc_0(sa) ; + return 1 ; +} + +int main (int argc, char const *const *argv, char const *const *envp) +{ + PROG = "s6-dnsname-filter" ; + return s6dns_generic_filter_main(argc, argv, envp, S6DNS_T_PTR, &ipscanner, &domainformatter, USAGE) ; +} diff --git a/src/clients/s6-dnsname.c b/src/clients/s6-dnsname.c new file mode 100644 index 0000000..d65da3a --- /dev/null +++ b/src/clients/s6-dnsname.c @@ -0,0 +1,75 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/fmtscan.h> +#include <skalibs/tai.h> +#include <skalibs/genalloc.h> +#include <skalibs/ip46.h> +#include <skalibs/random.h> +#include <skalibs/s6dns.h> + +#define USAGE "s6-dnsname [ -4 | -6 ] [ -r ] [ -t timeout ] ip" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + genalloc ds = GENALLOC_ZERO ; /* array of s6dns_domain_t */ + tain_t deadline ; + ip46full_t ip = IP46FULL_ZERO ; + unsigned int i = 0 ; + int flagunsort = 0 ; + int do4 = 0 ; + int do6 = 0 ; + PROG = "s6-dnsname" ; + for (;;) + { + register int opt = subgetopt(argc, argv, "46rt:") ; + if (opt == -1) break ; + switch (opt) + { + case '4' : do4 = 1 ; break ; + case '6' : do6 = 1 ; break ; + case 'r' : flagunsort = 1 ; break ; + case 't' : if (!uint0_scan(subgetopt_here.arg, &i)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= subgetopt_here.ind ; argv += subgetopt_here.ind ; + if (argc < 1) dieusage() ; + if (!do4 && !do6) do4 = do6 = 1 ; + if (do4 && do6) + { + if (!ip46full_scan(argv[0], &ip)) dieusage() ; + } + else if (do6) + { + if (!ip6_scan(argv[0], ip.ip)) dieusage() ; + ip.is6 = 1 ; + } + else if (!ip4_scan(argv[0], ip.ip)) dieusage() ; + + tain_now_g() ; + if (i) tain_from_millisecs(&deadline, i) ; else deadline = tain_infinite_relative ; + tain_add_g(&deadline, &deadline) ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + { + register int r = ip.is6 ? s6dns_resolve_name6_g(&ds, ip.ip, &deadline) : s6dns_resolve_name4_g(&ds, ip.ip, &deadline) ; + if (r < 0) strerr_diefu2sys((errno == ETIMEDOUT) ? 99 : 111, "resolve ", argv[0]) ; + if (!r) strerr_diefu4x(2, "resolve ", argv[0], ": ", s6dns_constants_error_str(errno)) ; + } + if (!genalloc_len(s6dns_domain_t, &ds)) return 1 ; + if (flagunsort) random_unsort(ds.s, genalloc_len(s6dns_domain_t, &ds), sizeof(s6dns_domain_t)) ; + { + char buf[S6DNS_FMT_DOMAINLIST(genalloc_len(s6dns_domain_t, &ds))] ; + unsigned int len = s6dns_fmt_domainlist(buf, S6DNS_FMT_DOMAINLIST(genalloc_len(s6dns_domain_t, &ds)), genalloc_s(s6dns_domain_t, &ds), genalloc_len(s6dns_domain_t, &ds), "\n", 1) ; + if (!len) strerr_diefu1sys(111, "format result") ; + if (buffer_putalign(buffer_1, buf, len) < 0) goto err ; + } + if (buffer_putflush(buffer_1, "\n", 1) < 0) goto err ; + return 0 ; + err: + strerr_diefu1sys(111, "write to stdout") ; +} diff --git a/src/clients/s6-dnsns.c b/src/clients/s6-dnsns.c new file mode 100644 index 0000000..d1caba5 --- /dev/null +++ b/src/clients/s6-dnsns.c @@ -0,0 +1,61 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/tai.h> +#include <skalibs/genalloc.h> +#include <skalibs/random.h> +#include <s6-dns/s6dns.h> + +#define USAGE "s6-dnsns [ -q ] [ -r ] [ -t timeout ] name" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + genalloc ds = GENALLOC_ZERO ; /* array of s6dns_domain_t */ + tain_t deadline ; + unsigned int i = 0 ; + int flagqualify = 0 ; + int flagunsort = 0 ; + PROG = "s6-dnsns" ; + for (;;) + { + register int opt = subgetopt(argc, argv, "qrt:") ; + if (opt == -1) break ; + switch (opt) + { + case 'q' : flagqualify = 1 ; break ; + case 'r' : flagunsort = 1 ; break ; + case 't' : if (!uint0_scan(subgetopt_here.arg, &i)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= subgetopt_here.ind ; argv += subgetopt_here.ind ; + if (argc < 1) dieusage() ; + + tain_now_g() ; + if (i) tain_from_millisecs(&deadline, i) ; else deadline = tain_infinite_relative ; + tain_add_g(&deadline, &deadline) ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + { + register int r = s6dns_resolve_ns_g(&ds, argv[0], str_len(argv[0]), flagqualify, &deadline) ; + if (r < 0) strerr_diefu2sys((errno == ETIMEDOUT) ? 99 : 111, "resolve ", argv[0]) ; + if (!r) strerr_diefu4x(2, "resolve ", argv[0], ": ", s6dns_constants_error_str(errno)) ; + } + if (!genalloc_len(s6dns_domain_t, &ds)) return 1 ; + if (flagunsort) random_unsort(ds.s, genalloc_len(s6dns_domain_t, &ds), sizeof(s6dns_domain_t)) ; + { + char buf[S6DNS_FMT_DOMAINLIST(genalloc_len(s6dns_domain_t, &ds))] ; + unsigned int len = s6dns_fmt_domainlist(buf, S6DNS_FMT_DOMAINLIST(genalloc_len(s6dns_domain_t, &ds)), genalloc_s(s6dns_domain_t, &ds), genalloc_len(s6dns_domain_t, &ds), "\n", 1) ; + if (!len) strerr_diefu1sys(111, "format result") ; + if (buffer_put(buffer_1, buf, len) < 0) goto err ; + } + if (buffer_putflush(buffer_1, "\n", 1) < 0) goto err ; + return 0 ; + err: + strerr_diefu1sys(111, "write to stdout") ; +} diff --git a/src/clients/s6-dnsq.c b/src/clients/s6-dnsq.c new file mode 100644 index 0000000..76ca4ea --- /dev/null +++ b/src/clients/s6-dnsq.c @@ -0,0 +1,99 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/bitarray.h> +#include <skalibs/strerr2.h> +#include <skalibs/sgetopt.h> +#include <skalibs/buffer.h> +#include <skalibs/genwrite.h> +#include <skalibs/tai.h> +#include <skalibs/ip46.h> +#include <s6-dns/s6dns.h> +#include <s6-dns/s6dns-analyze.h> +#include <s6-dns/s6dns-debug.h> + +#define USAGE "s6-dnsq [ -1 | -2 ] [ -t timeout ] [ -D debuglevel ] qtype query serverip..." +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + tain_t deadline ; + unsigned int debuglevel = 0 ; + uint16 qtype ; + genwrite_t *where = &genwrite_stderr ; + PROG = "s6-dnsq" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + unsigned int t = 0 ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "12t:D:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case '1' : where = &genwrite_stdout ; break ; + case '2' : where = &genwrite_stderr ; break ; + case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; + case 'D' : if (!uint0_scan(l.arg, &debuglevel)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (t) tain_from_millisecs(&deadline, t) ; else deadline = tain_infinite_relative ; + } + if (argc < 3) dieusage() ; + { + s6dns_debughook_t dbh = { .post_recv = 0, .pre_send = 0, .post_send = 0 } ; + s6dns_ip46list_t servers ; + s6dns_domain_t d ; + unsigned int i = 0, j = 0 ; + qtype = s6dns_analyze_qtype_parse(argv[0]) ; + if (!qtype) dieusage() ; + if (!s6dns_domain_fromstring_noqualify_encode(&d, argv[1], str_len(argv[1]))) + strerr_diefu2sys(100, "encode ", argv[1]) ; + dbh.external = where ; + byte_zero(&servers, sizeof(s6dns_ip46list_t)) ; + for (; (i < (unsigned int)(argc - 2)) && (j < S6DNS_MAX_SERVERS) ; i++) + { + ip46_t z[S6DNS_MAX_SERVERS] ; + unsigned int n ; + register unsigned int k = 0 ; + if (!*argv[2+i]) continue ; + if (!ip46_scanlist(z, S6DNS_MAX_SERVERS - j, argv[2 + i], &n)) + strerr_diefu2sys(100, "make an IP address list out of ", argv[2+i]) ; + for (; k < n ; k++) + { + byte_copy(s6dns_ip46list_ip(&servers, j + k), SKALIBS_IP_SIZE, z[k].ip) ; +#ifdef SKALIBS_IPV6_ENABLED + if (ip46_is6(z + k)) bitarray_set(servers.is6, j + k) ; +#endif + } + j += n ; + } + if (debuglevel & 1) dbh.post_recv = &s6dns_debug_dumpdt_post_recv ; + if (debuglevel & 2) { dbh.pre_send = &s6dns_debug_dumpdt_pre_send ; dbh.post_send = &s6dns_debug_dumpdt_post_send ; } + tain_now_g() ; + tain_add_g(&deadline, &deadline) ; + if (!s6dns_engine_init_r_g(&s6dns_engine_here, &servers, 0, d.s, d.len, qtype, &dbh, &deadline)) + strerr_diefu1sys(111, "initialize query") ; + } + if (!s6dns_resolve_loop_g(&deadline)) + { + char fmt[UINT16_FMT] ; + fmt[uint16_fmt(fmt, qtype)] = 0 ; + strerr_diefu6x((errno == ETIMEDOUT) ? 99 : 2, "resolve query ", argv[0], " of qtype ", fmt, ": ", s6dns_constants_error_str(errno)) ; + } + if (!s6dns_analyze_packet(&genwrite_stdout, s6dns_engine_packet(&s6dns_engine_here), s6dns_engine_packetlen(&s6dns_engine_here), 0)) + { + int e = errno ; + buffer_flush(buffer_1) ; + errno = e ; + strerr_diefu1sys(111, "analyze response") ; + } + if (!buffer_flush(buffer_1)) strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/clients/s6-dnsqr.c b/src/clients/s6-dnsqr.c new file mode 100644 index 0000000..1effe68 --- /dev/null +++ b/src/clients/s6-dnsqr.c @@ -0,0 +1,74 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/strerr2.h> +#include <skalibs/sgetopt.h> +#include <skalibs/buffer.h> +#include <skalibs/genwrite.h> +#include <skalibs/tai.h> +#include <s6-dns/s6dns.h> +#include <s6-dns/s6dns-analyze.h> +#include <s6-dns/s6dns-debug.h> + +#define USAGE "s6-dnsqr [ -1 | -2 ] [ -t timeout ] [ -D debuglevel ] qtype query" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + tain_t deadline ; + unsigned int debuglevel = 0 ; + genwrite_t *where = &genwrite_stderr ; + PROG = "s6-dnsqr" ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + unsigned int t = 0 ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "12t:D:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case '1' : where = &genwrite_stdout ; break ; + case '2' : where = &genwrite_stderr ; break ; + case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; + case 'D' : if (!uint0_scan(l.arg, &debuglevel)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (t) tain_from_millisecs(&deadline, t) ; else deadline = tain_infinite_relative ; + } + if (argc < 2) dieusage() ; + { + s6dns_debughook_t dbh = { .post_recv = 0, .pre_send = 0, .post_send = 0 } ; + s6dns_domain_t d ; + uint16 qtype = s6dns_analyze_qtype_parse(argv[0]) ; + if (!qtype) dieusage() ; + if (!s6dns_domain_fromstring_noqualify_encode(&d, argv[1], str_len(argv[1]))) + strerr_diefu2sys(100, "encode ", argv[1]) ; + dbh.external = where ; + if (debuglevel & 1) dbh.post_recv = &s6dns_debug_dumpdt_post_recv ; + if (debuglevel & 2) { dbh.pre_send = &s6dns_debug_dumpdt_pre_send ; dbh.post_send = &s6dns_debug_dumpdt_post_send ; } + tain_now_g() ; + tain_add_g(&deadline, &deadline) ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + if (!s6dns_resolve_core_r_g(&d, qtype, &s6dns_engine_here, &s6dns_rci_here.servers, &dbh, &deadline)) + { + char fmt[UINT16_FMT] ; + fmt[uint16_fmt(fmt, qtype)] = 0 ; + strerr_diefu6x((errno == ETIMEDOUT) ? 99 : 2, "resolve query ", argv[1], " of qtype ", fmt, ": ", s6dns_constants_error_str(errno)) ; + } + } + if (!s6dns_analyze_packet(&genwrite_stdout, s6dns_engine_packet(&s6dns_engine_here), s6dns_engine_packetlen(&s6dns_engine_here), 1)) + { + int e = errno ; + buffer_flush(buffer_1) ; + errno = e ; + strerr_diefu1sys(111, "analyze response") ; + } + if (!buffer_flush(buffer_1)) strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/clients/s6-dnsqualify.c b/src/clients/s6-dnsqualify.c new file mode 100644 index 0000000..64767ae --- /dev/null +++ b/src/clients/s6-dnsqualify.c @@ -0,0 +1,34 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <s6-dns/s6dns.h> + +#define USAGE "s6-dnsqualify name" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + s6dns_domain_t d ; + PROG = "s6-dnsqualify" ; + if (argc < 2) dieusage() ; + if (!s6dns_domain_fromstring(&d, argv[1], str_len(argv[1]))) + strerr_diefu2sys(100, "make a domain name from ", argv[1]) ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + { + s6dns_domain_t list[s6dns_rci_here.rulesnum] ; + unsigned int n = s6dns_qualify(list, &d) ; + if (!n) strerr_diefu2sys(111, "qualify ", argv[1]) ; + { + char buf[S6DNS_FMT_DOMAINLIST(n)] ; + unsigned int len = s6dns_fmt_domainlist(buf, S6DNS_FMT_DOMAINLIST(n), list, n, "\n", 1) ; + if (!len) strerr_diefu1sys(111, "format result") ; + if (buffer_put(buffer_1, buf, len) < 0) goto err ; + } + } + if (buffer_putflush(buffer_1, "\n", 1) < 0) goto err ; + return 0 ; + err: + strerr_diefu1sys(111, "write to stdout") ; +} diff --git a/src/clients/s6-dnssoa.c b/src/clients/s6-dnssoa.c new file mode 100644 index 0000000..1b02ff6 --- /dev/null +++ b/src/clients/s6-dnssoa.c @@ -0,0 +1,63 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/tai.h> +#include <skalibs/genalloc.h> +#include <skalibs/random.h> +#include <s6-dns/s6dns.h> + +#define USAGE "s6-dnssoa [ -q ] [ -r ] [ -t timeout ] name" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + genalloc soas = GENALLOC_ZERO ; /* array of s6dns_message_rr_soa_t */ + tain_t deadline ; + unsigned int i = 0 ; + int flagqualify = 0 ; + int flagunsort = 0 ; + PROG = "s6-dnssoa" ; + for (;;) + { + register int opt = subgetopt(argc, argv, "qrt:") ; + if (opt == -1) break ; + switch (opt) + { + case 'q' : flagqualify = 1 ; break ; + case 'r' : flagunsort = 1 ; break ; + case 't' : if (!uint0_scan(subgetopt_here.arg, &i)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= subgetopt_here.ind ; argv += subgetopt_here.ind ; + if (argc < 1) dieusage() ; + + tain_now_g() ; + if (i) tain_from_millisecs(&deadline, i) ; else deadline = tain_infinite_relative ; + tain_add_g(&deadline, &deadline) ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + { + register int r = s6dns_resolve_soa_g(&soas, argv[0], str_len(argv[0]), flagqualify, &deadline) ; + if (r < 0) strerr_diefu2sys((errno == ETIMEDOUT) ? 99 : 111, "resolve ", argv[0]) ; + if (!r) strerr_diefu4x(2, "resolve ", argv[0], ": ", s6dns_constants_error_str(errno)) ; + } + if (!genalloc_len(s6dns_message_rr_soa_t, &soas)) return 1 ; + if (flagunsort) random_unsort(soas.s, genalloc_len(s6dns_message_rr_soa_t, &soas), sizeof(s6dns_message_rr_soa_t)) ; + for (i = 0 ; i < genalloc_len(s6dns_message_rr_soa_t, &soas) ; i++) + { + char buf[S6DNS_FMT_SOA] ; + register unsigned int len = s6dns_fmt_soa(buf, S6DNS_FMT_SOA, genalloc_s(s6dns_message_rr_soa_t, &soas) + i) ; + if (!len) strerr_diefu1sys(111, "format result") ; + if (buffer_put(buffer_1, buf, len) < 0) goto err ; + if (buffer_put(buffer_1, "\n", 1) < 0) goto err ; + } + if (!buffer_flush(buffer_1)) goto err ; + return 0 ; + err: + strerr_diefu1sys(111, "write to stdout") ; +} diff --git a/src/clients/s6-dnssrv.c b/src/clients/s6-dnssrv.c new file mode 100644 index 0000000..283f1cd --- /dev/null +++ b/src/clients/s6-dnssrv.c @@ -0,0 +1,75 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/tai.h> +#include <skalibs/genalloc.h> +#include <skalibs/random.h> +#include <s6-dns/s6dns.h> + +#define USAGE "s6-dnssrv [ -q ] [ -r ] [ -t timeout ] service protocol name" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + genalloc srvs = GENALLOC_ZERO ; /* array of s6dns_message_rr_srv_t */ + tain_t deadline ; + unsigned int i = 0 ; + int flagqualify = 0 ; + int flagunsort = 0 ; + PROG = "s6-dnssrv" ; + for (;;) + { + register int opt = subgetopt(argc, argv, "qt:") ; + if (opt == -1) break ; + switch (opt) + { + case 'q' : flagqualify = 1 ; break ; + case 'r' : flagunsort = 1 ; break ; + case 't' : if (!uint0_scan(subgetopt_here.arg, &i)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= subgetopt_here.ind ; argv += subgetopt_here.ind ; + if (argc < 3) dieusage() ; + + tain_now_g() ; + if (i) tain_from_millisecs(&deadline, i) ; else deadline = tain_infinite_relative ; + tain_add_g(&deadline, &deadline) ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + { + unsigned int n0 = str_len(argv[0]) ; + unsigned int n1 = str_len(argv[1]) ; + unsigned int n2 = str_len(argv[2]) ; + char name[n0 + n1 + n2 + 5] ; + name[0] = '_' ; + byte_copy(name + 1, n0, argv[0]) ; + name[n0 + 1] = '.' ; + name[n0 + 2] = '_' ; + byte_copy(name + n0 + 3, n1, argv[1]) ; + name[n0 + n1 + 3] = '.' ; + byte_copy(name + n0 + n1 + 4, n2, argv[2]) ; + name[n0 + n1 + n2 + 4] = 0 ; + register int r = s6dns_resolve_srv_g(&srvs, name, n0 + n1 + n2 + 4, flagqualify, &deadline) ; + if (r < 0) strerr_diefu2sys((errno == ETIMEDOUT) ? 99 : 111, "resolve ", argv[0]) ; + if (!r) strerr_diefu4x(2, "resolve ", name, ": ", s6dns_constants_error_str(errno)) ; + } + if (!genalloc_len(s6dns_message_rr_srv_t, &srvs)) return 1 ; + if (flagunsort) random_unsort(srvs.s, genalloc_len(s6dns_message_rr_srv_t, &srvs), sizeof(s6dns_message_rr_srv_t)) ; + for (i = 0 ; i < genalloc_len(s6dns_message_rr_srv_t, &srvs) ; i++) + { + char buf[S6DNS_FMT_SRV] ; + register unsigned int len = s6dns_fmt_srv(buf, S6DNS_FMT_SRV, genalloc_s(s6dns_message_rr_srv_t, &srvs) + i) ; + if (!len) strerr_diefu1sys(111, "format result") ; + if (buffer_put(buffer_1, buf, len) < 0) goto err ; + if (buffer_put(buffer_1, "\n", 1) < 0) goto err ; + } + if (!buffer_flush(buffer_1)) goto err ; + return 0 ; + err: + strerr_diefu1sys(111, "write to stdout") ; +} diff --git a/src/clients/s6-dnstxt.c b/src/clients/s6-dnstxt.c new file mode 100644 index 0000000..fde69d2 --- /dev/null +++ b/src/clients/s6-dnstxt.c @@ -0,0 +1,78 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/tai.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/skamisc.h> +#include <skalibs/random.h> +#include <s6-dns/s6dns.h> + +#define USAGE "s6-dnstxt [ -q ] [ -r ] [ -t timeout ] name" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + stralloc quoted = STRALLOC_ZERO ; + stralloc sa = STRALLOC_ZERO ; + genalloc offsets = GENALLOC_ZERO ; /* array of unsigned int */ + tain_t deadline, stamp ; + unsigned int n ; + unsigned int i = 0 ; + int flagqualify = 0 ; + int flagunsort = 0 ; + PROG = "s6-dnstxt" ; + for (;;) + { + register int opt = subgetopt(argc, argv, "qrt:") ; + if (opt == -1) break ; + switch (opt) + { + case 'q' : flagqualify = 1 ; break ; + case 'r' : flagunsort = 1 ; break ; + case 't' : if (!uint0_scan(subgetopt_here.arg, &i)) dieusage() ; break ; + default : dieusage() ; + } + } + argc -= subgetopt_here.ind ; argv += subgetopt_here.ind ; + if (argc < 1) dieusage() ; + + tain_now(&stamp) ; + if (i) tain_from_millisecs(&deadline, i) ; else deadline = tain_infinite_relative ; + tain_add(&deadline, &deadline, &stamp) ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + { + register int r = s6dns_resolve_txt(&sa, &offsets, argv[0], str_len(argv[0]), flagqualify, &deadline, &stamp) ; + if (r < 0) strerr_diefu2sys((errno == ETIMEDOUT) ? 99 : 111, "resolve ", argv[0]) ; + if (!r) strerr_diefu4x(2, "resolve ", argv[0], ": ", s6dns_constants_error_str(errno)) ; + } + n = genalloc_len(unsigned int, &offsets) ; + if (!n) return 1 ; + { + unsigned int printable_offsets[n] ; + for (i = 0 ; i < n ; i++) + { + unsigned int beg = genalloc_s(unsigned int, &offsets)[i] ; + unsigned int end = (i < n-1 ? genalloc_s(unsigned int, &offsets)[i+1] : sa.len) - 1 ; + printable_offsets[i] = quoted.len ; + if (!string_quote("ed, sa.s + beg, end - beg) || !stralloc_0("ed)) + strerr_diefu2sys(111, "quote ", sa.s + beg) ; + } + genalloc_free(unsigned int, &offsets) ; + stralloc_free(&sa) ; + if (flagunsort) random_unsort((char *)printable_offsets, n, sizeof(unsigned int)) ; + for (i = 0 ; i < n ; i++) + if ((buffer_puts(buffer_1small, quoted.s + printable_offsets[i]) < 0) + || (buffer_put(buffer_1small, "\n", 1) < 1)) + strerr_diefu1sys(111, "write to stdout") ; + } + stralloc_free("ed) ; + if (!buffer_flush(buffer_1small)) + strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/clients/s6-randomip.c b/src/clients/s6-randomip.c new file mode 100644 index 0000000..b220374 --- /dev/null +++ b/src/clients/s6-randomip.c @@ -0,0 +1,62 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/buffer.h> +#include <skalibs/fmtscan.h> +#include <skalibs/random.h> + +#define USAGE "s6-randomip [ -4 ] [ -6 ] [ -n number ]" +#define dieusage() strerr_dieusage(100, USAGE) + +int main (int argc, char const *const *argv) +{ + char fmt[IP6_FMT] ; + char ip[16] ; + unsigned int n ; + unsigned int i = 0 ; + unsigned int what = 0 ; + int finite = 0 ; + PROG = "s6-randomip" ; + for (;;) + { + register int opt = subgetopt(argc, argv, "46n:") ; + if (opt == -1) break ; + switch (opt) + { + case '4' : what |= 1 ; break ; + case '6' : what |= 2 ; break ; + case 'n' : + if (!uint0_scan(subgetopt_here.arg, &n)) dieusage() ; + finite = 1 ; + break ; + default : dieusage() ; + } + } + argc -= subgetopt_here.ind ; argv += subgetopt_here.ind ; + if (!what) what = 1 ; + what = 1 << (1 << what) ; + if (!badrandom_init()) strerr_diefu1sys(111, "init RNG") ; + for (i = 0 ; !finite || (i < n) ; i++) + { + unsigned int len = what ; + if (len > 16) + { + char c ; + if (badrandom_string(&c, 1) < 1) + strerr_diefu1sys(111, "badrandom_string") ; + len = (c & 1) ? 16 : 4 ; + } + if (badrandom_string(ip, len) < 4) + strerr_diefu1sys(111, "badrandom_string") ; + len = (len == 16) ? ip6_fmt(fmt, ip) : ip4_fmt(fmt, ip) ; + fmt[len++] = '\n' ; + if (buffer_put(buffer_1, fmt, len) < (int)len) + strerr_diefu1sys(111, "write to stdout") ; + } + if (!buffer_flush(buffer_1)) + strerr_diefu1sys(111, "write to stdout") ; + return 0 ; +} diff --git a/src/clients/s6dns-generic-filter.h b/src/clients/s6dns-generic-filter.h new file mode 100644 index 0000000..53fa560 --- /dev/null +++ b/src/clients/s6dns-generic-filter.h @@ -0,0 +1,22 @@ +/* ISC license. */ + +#ifndef SKADNS_GENERIC_FILTER_H +#define SKADNS_GENERIC_FILTER_H + +#include <skalibs/uint16.h> +#include <skalibs/stralloc.h> +#include <s6-dns/s6dns-domain.h> + +typedef unsigned int scan_func_t (s6dns_domain_t *, char const *) ; +typedef scan_func_t *scan_func_t_ref ; +typedef int fmt_func_t (stralloc *, char const *, unsigned int) ; +typedef fmt_func_t *fmt_func_t_ref ; + +extern unsigned int s6dns_namescanner (s6dns_domain_t *, char const *) ; +extern int s6dns_domainformatter (stralloc *, char const *, unsigned int) ; +extern int s6dns_generic_filter_main (int, char const *const *, char const *const *, uint16, scan_func_t_ref, fmt_func_t_ref, char const *) ; + +extern int flag4 ; +extern int flag6 ; + +#endif diff --git a/src/clients/s6dns_generic_filter_main.c b/src/clients/s6dns_generic_filter_main.c new file mode 100644 index 0000000..430b0c3 --- /dev/null +++ b/src/clients/s6dns_generic_filter_main.c @@ -0,0 +1,230 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/uint16.h> +#include <skalibs/uint.h> +#include <skalibs/sgetopt.h> +#include <skalibs/strerr2.h> +#include <skalibs/env.h> +#include <skalibs/tai.h> +#include <skalibs/iopause.h> +#include <skalibs/djbunix.h> +#include <skalibs/stralloc.h> +#include <skalibs/buffer.h> +#include <skalibs/bufalloc.h> +#include <skalibs/skamisc.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/skadns.h> +#include "s6dns-generic-filter.h" + +#define dieusage() strerr_dief1x(100, USAGE) ; + +typedef struct line_s line_t, *line_t_ref ; +struct line_s +{ + stralloc swrd ; + unsigned int wpos ; + int dpos ; + char w[2] ; + unsigned int pending : 1 ; +} ; + +#define LINE_ZERO { STRALLOC_ZERO, 0, 0, "\0", 0 } + +static void line_recycle (line_t_ref l) +{ + l->swrd.len = 0 ; + l->pending = 0 ; +} + +int flag4 = 0 ; +int flag6 = 0 ; + +int s6dns_generic_filter_main (int argc, char const *const *argv, char const *const *envp, uint16 qtype, scan_func_t_ref scanner, fmt_func_t_ref formatter, char const *USAGE) +{ + skadns_t a = SKADNS_ZERO ; + tain_t deadline, tto ; + char const *normalformat = "%s=%d%w%r" ; + char const *errorformat = "%s=<%e>%w%r" ; + uint16 maxlines = 256 ; + uint16 maxconn = 128 ; + { + subgetopt_t l = SUBGETOPT_ZERO ; + unsigned int t = 0 ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, (qtype == S6DNS_T_PTR) ? "46l:c:t:f:e:" : "l:c:t:f:e:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case '4' : flag4 = 1 ; break ; + case '6' : flag6 = 1 ; break ; + case 'l' : if (!uint160_scan(l.arg, &maxlines)) dieusage() ; break ; + case 'c' : if (!uint160_scan(l.arg, &maxconn)) dieusage() ; break ; + case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; + case 'f' : normalformat = l.arg ; break ; + case 'e' : errorformat = l.arg ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + if (t) tain_from_millisecs(&tto, t) ; else tto = tain_infinite_relative ; + } + if (!flag4 && !flag6) flag4 = 1 ; + if (maxconn < 1) maxconn = 1 ; + if (maxconn > SKADNS_MAXCONCURRENCY) maxconn = SKADNS_MAXCONCURRENCY ; + if (maxlines < maxconn) maxlines = maxconn ; + + tain_now_g() ; + tain_addsec_g(&deadline, 2) ; + if (!skadns_startf_g(&a, &deadline)) + strerr_diefu1sys(111, "establish skadns connection") ; + if ((ndelay_on(0) < 0) || (ndelay_on(1) < 0)) + strerr_diefu1sys(111, "ndelay_on") ; + + { + iopause_fd x[3] = { { 0, 0, 0 }, { 1, 0, 0 }, { -1, 0, 0 } } ; + uint16 lhead = 0, ltail = 0, numlines = 0, pending = 0 ; + line_t storage[maxlines+1] ; + uint16 lineindex[maxconn] ; + x[2].fd = skadns_fd(&a) ; + { + line_t line_zero = LINE_ZERO ; + char const *args[4] = { "", "", "", "" } ; + uint16 i = 0 ; + for (; i <= maxlines ; i++) storage[i] = line_zero ; + if (!string_format(&storage[0].swrd, "sdwr", normalformat, args) + || !string_format(&storage[0].swrd, "sewr", errorformat, args)) + strerr_diefu1sys(111, "format a string") ; + storage[0].swrd.len = 0 ; + } + + for (;;) + { + x[0].events = !x[0].fd && (numlines < maxlines) && (pending < maxconn) ? IOPAUSE_READ : 0 ; + x[1].events = bufalloc_len(bufalloc_1) ? IOPAUSE_WRITE : 0 ; + x[2].events = pending ? IOPAUSE_READ : 0 ; + if (!x[0].events && !x[1].events && !x[2].events) break ; + tain_add_g(&deadline, &tain_infinite_relative) ; + + if (iopause_g(x + !(x[0].events & IOPAUSE_READ), 3 - !(x[0].events & IOPAUSE_READ), &deadline) < 0) + strerr_diefu1sys(111, "iopause") ; + + + /* Flush stdout */ + + if (x[1].revents) + { + if (!bufalloc_flush(bufalloc_1) && !error_isagain(errno)) + strerr_diefu1sys(111, "write to stdout") ; + } + + + /* Get and format results from skadnsd */ + + if (x[2].revents) + { + register int j = 0 ; + register uint16 const *list ; + int n = skadns_update(&a) ; + if (n < 0) strerr_diefu1sys(111, "skadns_update") ; + list = skadns_list(&a) ; + for (; j < n ; j++) + { + register uint16 i = lineindex[list[j]] ; + register char const *packet = skadns_packet(&a, list[j]) ; + if (packet) + { + register int r ; + r = (*formatter)(&storage[i].swrd, packet, skadns_packetlen(&a, list[j])) ; + if (r < 0) strerr_diefu1sys(111, "format skadns answer") ; + if (!r) storage[i].dpos = -errno ; + } + else storage[i].dpos = -errno ; + storage[i].pending = 0 ; + skadns_release(&a, list[j]) ; + pending-- ; + } + skadns_clearlist(&a) ; + } + + + /* Scan stdin and send queries to skadnsd */ + + if (buffer_len(buffer_0) || (!x[0].fd && x[0].revents)) + { + for (; (numlines < maxlines) && (pending < maxconn) ; lhead = (lhead+1) % (maxlines+1), numlines++) + { + s6dns_domain_t d ; + register line_t_ref line = storage + lhead ; + register int r = skagetln(buffer_0, &line->swrd, '\n') ; + if (r < 0) + { + if (error_isagain(errno)) break ; + if (errno != EPIPE) strerr_diefu1sys(111, "read from stdin") ; + if (!stralloc_catb(&line->swrd, "\n", 1)) strerr_diefu1sys(111, "stralloc_catb") ; + x[0].fd = -1 ; + break ; + } + else if (!r) + { + x[0].fd = -1 ; + break ; + } + line->swrd.s[line->swrd.len-1] = 0 ; + line->wpos = (*scanner)(&d, line->swrd.s) ; + if (!line->wpos) + { + line->wpos = line->swrd.len - 1 ; + line->w[0] = 0 ; + line->dpos = -errno ; + } + else + { + tain_t sendlimit ; + uint16 id ; + line->w[0] = line->swrd.s[line->wpos] ; + line->swrd.s[line->wpos] = 0 ; + tain_addsec_g(&sendlimit, 2) ; + tain_add_g(&deadline, &tto) ; + if (!skadns_send_g(&a, &id, &d, qtype, &deadline, &sendlimit)) + line->dpos = -errno ; + else + { + line->dpos = line->swrd.len ; + lineindex[id] = lhead ; + line->pending = 1 ; + pending++ ; + } + } + } + } + + if (x[0].revents & IOPAUSE_EXCEPT) x[0].fd = -1 ; + + + /* Send processed lines to stdout */ + + for (; ltail != lhead ; ltail = (ltail+1) % (maxlines+1), numlines--) + { + char *args[4] ; + register line_t_ref line = storage + ltail ; + if (line->pending) break ; + args[0] = line->swrd.s ; + args[1] = line->dpos < 0 ? (char *)s6dns_constants_error_str(-line->dpos) : line->swrd.s + line->dpos ; + args[2] = line->w ; + args[3] = line->swrd.s + line->wpos + !!line->w[0] ; + if (!string_format(&bufalloc_1->x, line->dpos < 0 ? "sewr" : "sdwr", line->dpos < 0 ? errorformat : normalformat, (char const **)args)) + strerr_diefu1sys(111, "format output line") ; + line_recycle(line) ; + if (!bufalloc_put(bufalloc_1, "\n", 1)) + strerr_diefu1sys(111, "bufalloc_put") ; + } + } + } + + (void)envp ; + return 0 ; +} diff --git a/src/clients/s6dns_namescanner.c b/src/clients/s6dns_namescanner.c new file mode 100644 index 0000000..b23fb3d --- /dev/null +++ b/src/clients/s6dns_namescanner.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-generic-filter.h> + +unsigned int s6dns_namescanner (s6dns_domain_t *d, char const *s) +{ + register unsigned int pos = 0 ; + while (s[pos] && (s[pos] != ' ') && (s[pos] != '\t') && (s[pos] != '\r') && (s[pos] != '\n')) pos++ ; + if (!s6dns_domain_fromstring_noqualify_encode(d, s, pos)) return 0 ; + return pos ; +} 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 diff --git a/src/libs6dns/deps-lib/s6dns b/src/libs6dns/deps-lib/s6dns new file mode 100755 index 0000000..b218652 --- /dev/null +++ b/src/libs6dns/deps-lib/s6dns @@ -0,0 +1,88 @@ +s6dns_constants_error.o +s6dns_constants_error_str.o +s6dns_debughook_zero.o +s6dns_domain_arpafromip4.o +s6dns_domain_arpafromip6.o +s6dns_domain_decode.o +s6dns_domain_encode.o +s6dns_domain_encodelist.o +s6dns_domain_fromstring.o +s6dns_domain_fromstring_noqualify_encode.o +s6dns_domain_fromstring_qualify_encode.o +s6dns_domain_noqualify.o +s6dns_domain_qualify.o +s6dns_domain_tostring.o +s6dns_engine.o +s6dns_engine_free.o +s6dns_engine_freen.o +s6dns_engine_here.o +s6dns_engine_nextdeadline.o +s6dns_engine_zero.o +s6dns_fmt_domainlist.o +s6dns_fmt_hinfo.o +s6dns_fmt_mx.o +s6dns_fmt_soa.o +s6dns_fmt_srv.o +s6dns_message_counts_next.o +s6dns_message_counts_pack.o +s6dns_message_counts_unpack.o +s6dns_message_counts_zero.o +s6dns_message_get_domain.o +s6dns_message_get_domain_internal.o +s6dns_message_get_hinfo.o +s6dns_message_get_string.o +s6dns_message_get_string_internal.o +s6dns_message_get_strings.o +s6dns_message_get_mx.o +s6dns_message_get_soa.o +s6dns_message_get_srv.o +s6dns_message_header_pack.o +s6dns_message_header_unpack.o +s6dns_message_header_zero.o +s6dns_message_parse_answer_aaaa.o +s6dns_message_parse_answer_a.o +s6dns_message_parse_answer_domain.o +s6dns_message_parse_answer_hinfo.o +s6dns_message_parse_answer_mx.o +s6dns_message_parse_answer_soa.o +s6dns_message_parse_answer_srv.o +s6dns_message_parse_answer_strings.o +s6dns_message_parse.o +s6dns_message_parse_getrr.o +s6dns_message_parse_init.o +s6dns_message_parse_next.o +s6dns_message_parse_skipqd.o +s6dns_rci_free.o +s6dns_rci_here.o +s6dns_rci_init.o +s6dns_rci_zero.o +s6dns_resolve_core.o +s6dns_resolve_parse.o +s6dns_resolven_loop.o +s6dns_resolven_parse.o +s6dns_resolve_dpag.o +s6dns_resolve_mpag.o +s6dns_resolve_name4.o +s6dns_resolve_name6.o +s6dns_resolvenoq.o +s6dns_resolveq.o +s6dns_resolvenoq_aaaaa.o +s6dns_resolveq_aaaaa.o +s6dns_analyze_packet.o +s6dns_analyze_qtype_parse.o +s6dns_analyze_record.o +s6dns_analyze_record_a.o +s6dns_analyze_record_aaaa.o +s6dns_analyze_record_hinfo.o +s6dns_analyze_record_mx.o +s6dns_analyze_record_soa.o +s6dns_analyze_record_srv.o +s6dns_analyze_record_domain.o +s6dns_analyze_record_strings.o +s6dns_analyze_record_unknown.o +s6dns_analyze_rtypetable.o +s6dns_debug_dumpdt_stdout.o +s6dns_debug_dumpdt_stderr.o +s6dns_debug_dumpdt_post_recv.o +s6dns_debug_dumpdt_pre_send.o +s6dns_debug_dumpdt_post_send.o diff --git a/src/libs6dns/s6dns-message-internal.h b/src/libs6dns/s6dns-message-internal.h new file mode 100644 index 0000000..e0d10d6 --- /dev/null +++ b/src/libs6dns/s6dns-message-internal.h @@ -0,0 +1,12 @@ +/* ISC license. */ + +#ifndef S6DNS_MESSAGE_INTERNAL_H +#define S6DNS_MESSAGE_INTERNAL_H + + + /* Low-level packet parsing */ + +extern int s6dns_message_get_string_internal (char *, unsigned int, char const *, unsigned int, unsigned int *) ; +extern unsigned int s6dns_message_get_domain_internal (char *, unsigned int, char const *, unsigned int, unsigned int *) ; + +#endif diff --git a/src/libs6dns/s6dns_analyze_packet.c b/src/libs6dns/s6dns_analyze_packet.c new file mode 100644 index 0000000..57a5ce5 --- /dev/null +++ b/src/libs6dns/s6dns_analyze_packet.c @@ -0,0 +1,127 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/uint16.h> +#include <skalibs/bytestr.h> +#include <skalibs/genwrite.h> +#include <skalibs/fmtscan.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-analyze.h> + +#define add(s) if ((*gp->put)(gp->target, (s), str_len(s)) < 0) return 0 +#define addfmt(n) if ((*gp->put)(gp->target, fmt, uint_fmt(fmt, (n))) < 0) return 0 +#define addfmt16(n) if ((*gp->put)(gp->target, fmt, uint16_fmt(fmt, (n))) < 0) return 0 + +int s6dns_analyze_packet (genwrite_t *gp, char const *packet, unsigned int packetlen, int rec) +{ + s6dns_message_header_t h ; + s6dns_message_counts_t counts ; + unsigned int pos ; + unsigned int section ; + char fmt[UINT_FMT] ; + if (!s6dns_message_parse_init(&h, &counts, packet, packetlen, &pos)) + return 0 ; + + addfmt(packetlen) ; + add(" bytes, ") ; + addfmt16(counts.qd) ; + add("+") ; + addfmt16(counts.an) ; + add("+") ; + addfmt16(counts.ns) ; + add("+") ; + addfmt16(counts.nr) ; + add(" records") ; + if (h.qr) add(", response") ; + if (h.opcode) + { + add(", weird op (") ; + addfmt(h.opcode) ; + add(")") ; + } + if (h.aa) add(", authoritative") ; + if (h.tc) add(", truncated") ; + if (h.rd) + { + add(", ") ; + if (!rec) add("weird ") ; + add("rd") ; + } + if (h.ra) + { + add(", ") ; + if (!rec) add("weird ") ; + add("ra") ; + } + switch (h.rcode) + { + case 0 : add(", noerror") ; break ; + case 1 : add(", fmterror") ; break ; + case 2 : add(", servfail") ; break ; + case 3 : add(", nxdomain") ; break ; + case 4 : add(", notimpl") ; break ; + case 5 : add(", refused") ; break ; + default: + { + add(", weird rcode (") ; + addfmt(h.rcode) ; + add(")") ; + } + } + if (h.z) + { + add(", weird z (") ; + addfmt(h.z) ; + add(")") ; + } + add("\n") ; + + for (;;) + { + s6dns_domain_t d ; + char buf[257] ; + unsigned int len ; + uint16 qtype ; + uint16 qclass ; + section = s6dns_message_counts_next(&counts) ; + if (section != 1) break ; + add("query: ") ; + if (!s6dns_message_get_domain(&d, packet, packetlen, &pos)) return 0 ; + len = s6dns_domain_tostring(buf, 255, &d) ; + if (!len) return 0 ; + buf[len++] = '\n' ; buf[len++] = 0 ; + if (pos + 4 > packetlen) return (errno = EPROTO, 0) ; + uint16_unpack_big(packet + pos, &qtype) ; pos += 2 ; + uint16_unpack_big(packet + pos, &qclass) ; pos += 2 ; + if (qclass != S6DNS_C_IN) + { + add("weird class (") ; + addfmt16(qclass) ; + add(") - ") ; + } + addfmt16(qtype) ; + add(" ") ; + add(buf) ; + } + + while (section) + { + static char const *intro[3] = { "answer: ", "authority: ", "additional: " } ; + s6dns_message_rr_t rr ; + if (!s6dns_message_parse_getrr(&rr, packet, packetlen, &pos)) return 0 ; + add(intro[section-2]) ; + if (rr.rclass != S6DNS_C_IN) + { + add("weird class (") ; + addfmt16(rr.rclass) ; + add("), not attempting to analyze record\n") ; + } + else if (!s6dns_analyze_record(gp, &rr, packet, packetlen, pos)) return 0 ; + section = s6dns_message_parse_next(&counts, &rr, packet, packetlen, &pos) ; + } + + return 1 ; +} diff --git a/src/libs6dns/s6dns_analyze_qtype_parse.c b/src/libs6dns/s6dns_analyze_qtype_parse.c new file mode 100644 index 0000000..8c04137 --- /dev/null +++ b/src/libs6dns/s6dns_analyze_qtype_parse.c @@ -0,0 +1,46 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <skalibs/bytestr.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-analyze.h> + +typedef struct lookuptable_s lookuptable_t, *lookuptable_t_ref ; +struct lookuptable_s +{ + char const *text ; + uint16 qtype ; +} ; + +static lookuptable_t const table[] = +{ + { "ANY", S6DNS_T_ANY }, + { "A", S6DNS_T_A }, + { "NS", S6DNS_T_NS }, + { "CNAME", S6DNS_T_CNAME }, + { "SOA", S6DNS_T_SOA }, + { "PTR", S6DNS_T_PTR }, + { "HINFO", S6DNS_T_HINFO }, + { "MX", S6DNS_T_MX }, + { "TXT", S6DNS_T_TXT }, + { "AAAA", S6DNS_T_AAAA }, + { "SRV", S6DNS_T_SRV }, + { "RP", S6DNS_T_RP }, + { "SIG", S6DNS_T_SIG }, + { "KEY", S6DNS_T_KEY }, + { "AXFR", S6DNS_T_AXFR }, + { 0, 0 } +} ; + +uint16 s6dns_analyze_qtype_parse (char const *s) +{ + { + uint16 u ; + if (uint160_scan(s, &u)) return u ; + } + { + register lookuptable_t const *p = table ; + for (; p->text ; p++) if (case_equals(s, p->text)) return p->qtype ; + } + return 0 ; +} diff --git a/src/libs6dns/s6dns_analyze_record.c b/src/libs6dns/s6dns_analyze_record.c new file mode 100644 index 0000000..dd2e7d2 --- /dev/null +++ b/src/libs6dns/s6dns_analyze_record.c @@ -0,0 +1,37 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <skalibs/bytestr.h> +#include <skalibs/genwrite.h> +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-analyze.h> + +static s6dns_analyze_rtypetable_t const *rtypelookup (uint16 rtype) +{ + register s6dns_analyze_rtypetable_t const *wut = s6dns_analyze_rtypetable ; + while (wut->rtype && wut->rtype != rtype) wut++ ; + return wut ; +} + +int s6dns_analyze_record (genwrite_t *gp, s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos) +{ + s6dns_analyze_rtypetable_t const *wut = rtypelookup(rr->rtype) ; + { + char buf[256] ; + register unsigned int n = s6dns_domain_tostring(buf, 256, &rr->name) ; + if (!n) return 0 ; + if ((*gp->put)(gp->target, buf, n) < 0) return 0 ; + } + { + char fmt[UINT32_FMT+1] = " " ; + if ((*gp->put)(gp->target, fmt, 1 + uint32_fmt(fmt+1, rr->ttl)) < 0) return 0 ; + } + if ((*gp->put)(gp->target, " ", 1) < 0) return 0 ; + if ((*gp->put)(gp->target, wut->string, str_len(wut->string)) < 0) return 0 ; + if ((*gp->put)(gp->target, " ", 1) < 0) return 0 ; + if (!(*wut->f)(gp, rr, packet, packetlen, pos)) return 0 ; + if ((*gp->put)(gp->target, "\n", 1) < 0) return 0 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_analyze_record_a.c b/src/libs6dns/s6dns_analyze_record_a.c new file mode 100644 index 0000000..5e374cb --- /dev/null +++ b/src/libs6dns/s6dns_analyze_record_a.c @@ -0,0 +1,17 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genwrite.h> +#include <skalibs/fmtscan.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-analyze.h> + +int s6dns_analyze_record_a (genwrite_t *gp, s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos) +{ + char fmt[IP4_FMT] ; + if (rr->rdlength != 4) return (errno = EPROTO, 0) ; + if (pos + 4 > packetlen) return (errno = EPROTO, 0) ; + if ((*gp->put)(gp->target, fmt, ip4_fmt(fmt, packet + pos)) < 0) return 0 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_analyze_record_aaaa.c b/src/libs6dns/s6dns_analyze_record_aaaa.c new file mode 100644 index 0000000..495ba24 --- /dev/null +++ b/src/libs6dns/s6dns_analyze_record_aaaa.c @@ -0,0 +1,17 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genwrite.h> +#include <skalibs/fmtscan.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-analyze.h> + +int s6dns_analyze_record_aaaa (genwrite_t *gp, s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos) +{ + char fmt[IP6_FMT] ; + if (rr->rdlength != 16) return (errno = EPROTO, 0) ; + if (pos + 16 > packetlen) return (errno = EPROTO, 0) ; + if ((*gp->put)(gp->target, fmt, ip6_fmt(fmt, packet + pos)) < 0) return 0 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_analyze_record_domain.c b/src/libs6dns/s6dns_analyze_record_domain.c new file mode 100644 index 0000000..f645dca --- /dev/null +++ b/src/libs6dns/s6dns_analyze_record_domain.c @@ -0,0 +1,23 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genwrite.h> +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-fmt.h> +#include <s6-dns/s6dns-analyze.h> + +int s6dns_analyze_record_domain (genwrite_t *gp, s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int start) +{ + s6dns_domain_t d ; + char buf[S6DNS_FMT_DOMAIN] ; + unsigned int pos = start ; + register unsigned int len ; + if (!s6dns_message_get_domain(&d, packet, packetlen, &pos)) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + len = s6dns_fmt_domain(buf, 256, &d) ; + if (!len) return 0 ; + if ((*gp->put)(gp->target, buf, len) < 0) return 0 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_analyze_record_hinfo.c b/src/libs6dns/s6dns_analyze_record_hinfo.c new file mode 100644 index 0000000..38d13d9 --- /dev/null +++ b/src/libs6dns/s6dns_analyze_record_hinfo.c @@ -0,0 +1,22 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genwrite.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-fmt.h> +#include <s6-dns/s6dns-analyze.h> + +int s6dns_analyze_record_hinfo (genwrite_t *gp, s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int start) +{ + s6dns_message_rr_hinfo_t hinfo ; + char buf[S6DNS_FMT_HINFO] ; + unsigned int pos = start ; + unsigned int len ; + if (!s6dns_message_get_hinfo(&hinfo, packet, packetlen, &pos)) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + len = s6dns_fmt_hinfo(buf, S6DNS_FMT_HINFO, &hinfo) ; + if (!len) return 0 ; + if ((*gp->put)(gp->target, buf, len) < 0) return 0 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_analyze_record_mx.c b/src/libs6dns/s6dns_analyze_record_mx.c new file mode 100644 index 0000000..adf9995 --- /dev/null +++ b/src/libs6dns/s6dns_analyze_record_mx.c @@ -0,0 +1,22 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genwrite.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-fmt.h> +#include <s6-dns/s6dns-analyze.h> + +int s6dns_analyze_record_mx (genwrite_t *gp, s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int start) +{ + s6dns_message_rr_mx_t mx ; + char buf[S6DNS_FMT_MX] ; + unsigned int pos = start ; + unsigned int len ; + if (!s6dns_message_get_mx(&mx, packet, packetlen, &pos)) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + len = s6dns_fmt_mx(buf, S6DNS_FMT_MX, &mx) ; + if (!len) return 0 ; + if ((*gp->put)(gp->target, buf, len) < 0) return 0 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_analyze_record_soa.c b/src/libs6dns/s6dns_analyze_record_soa.c new file mode 100644 index 0000000..68fc55f --- /dev/null +++ b/src/libs6dns/s6dns_analyze_record_soa.c @@ -0,0 +1,22 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genwrite.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-fmt.h> +#include <s6-dns/s6dns-analyze.h> + +int s6dns_analyze_record_soa (genwrite_t *gp, s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int start) +{ + s6dns_message_rr_soa_t soa ; + char buf[S6DNS_FMT_SOA] ; + unsigned int pos = start ; + unsigned int len ; + if (!s6dns_message_get_soa(&soa, packet, packetlen, &pos)) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + len = s6dns_fmt_soa(buf, S6DNS_FMT_SOA, &soa) ; + if (!len) return 0 ; + if ((*gp->put)(gp->target, buf, len) < 0) return 0 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_analyze_record_srv.c b/src/libs6dns/s6dns_analyze_record_srv.c new file mode 100644 index 0000000..9ce5b6e --- /dev/null +++ b/src/libs6dns/s6dns_analyze_record_srv.c @@ -0,0 +1,22 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genwrite.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-fmt.h> +#include <s6-dns/s6dns-analyze.h> + +int s6dns_analyze_record_srv (genwrite_t *gp, s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int start) +{ + s6dns_message_rr_srv_t srv ; + char buf[S6DNS_FMT_SRV] ; + unsigned int pos = start ; + unsigned int len ; + if (!s6dns_message_get_srv(&srv, packet, packetlen, &pos)) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + len = s6dns_fmt_srv(buf, S6DNS_FMT_SRV, &srv) ; + if (!len) return 0 ; + if ((*gp->put)(gp->target, buf, len) < 0) return 0 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_analyze_record_strings.c b/src/libs6dns/s6dns_analyze_record_strings.c new file mode 100644 index 0000000..c2aa15a --- /dev/null +++ b/src/libs6dns/s6dns_analyze_record_strings.c @@ -0,0 +1,23 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/stralloc.h> +#include <skalibs/genwrite.h> +#include <skalibs/skamisc.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-analyze.h> + +int s6dns_analyze_record_strings (genwrite_t *gp, s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int start) +{ + stralloc sa = STRALLOC_ZERO ; + char buf[rr->rdlength] ; + unsigned int pos = start ; + register int r = s6dns_message_get_strings(buf, rr->rdlength, packet, packetlen, &pos) ; + if (r < 0) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + if (!string_quote(&sa, buf, r)) return 0 ; + r = (*gp->put)(gp->target, sa.s, sa.len) >= 0 ; + stralloc_free(&sa) ; + return r ; +} diff --git a/src/libs6dns/s6dns_analyze_record_unknown.c b/src/libs6dns/s6dns_analyze_record_unknown.c new file mode 100644 index 0000000..b5e458e --- /dev/null +++ b/src/libs6dns/s6dns_analyze_record_unknown.c @@ -0,0 +1,25 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <skalibs/fmtscan.h> +#include <skalibs/genwrite.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-analyze.h> + +int s6dns_analyze_record_unknown (genwrite_t *gp, s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos) +{ + char fmt[UINT16_FMT] ; + if ((*gp->put)(gp->target, "rtype ", 6) < 0) return 0 ; + if ((*gp->put)(gp->target, fmt, uint16_fmt(fmt, rr->rtype)) < 0) return 0 ; + if ((*gp->put)(gp->target, " length ", 8) < 0) return 0 ; + if ((*gp->put)(gp->target, fmt, uint16_fmt(fmt, rr->rdlength)) < 0) return 0 ; + if ((*gp->put)(gp->target, ": ", 2) < 0) return 0 ; + { + register uint16 i = 0 ; + for (; i < rr->rdlength ; i++) + if ((*gp->put)(gp->target, fmt, ucharn_fmt(fmt, packet + pos + i, 1)) < 0) + return 0 ; + } + (void)packetlen ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_analyze_rtypetable.c b/src/libs6dns/s6dns_analyze_rtypetable.c new file mode 100644 index 0000000..523fc72 --- /dev/null +++ b/src/libs6dns/s6dns_analyze_rtypetable.c @@ -0,0 +1,20 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-analyze.h> + +static s6dns_analyze_rtypetable_t const s6dns_analyze_rtypetable_array[] = +{ + { 1, "A", &s6dns_analyze_record_a }, + { 2, "NS", &s6dns_analyze_record_domain }, + { 5, "CNAME", &s6dns_analyze_record_domain }, + { 6, "SOA", &s6dns_analyze_record_soa }, + { 12, "PTR", &s6dns_analyze_record_domain }, + { 13, "HINFO", &s6dns_analyze_record_hinfo }, + { 15, "MX", &s6dns_analyze_record_mx }, + { 16, "TXT", &s6dns_analyze_record_strings }, + { 28, "AAAA", &s6dns_analyze_record_aaaa }, + { 33, "SRV", &s6dns_analyze_record_srv }, + { 0, "unknown", &s6dns_analyze_record_unknown } +} ; + +s6dns_analyze_rtypetable_t const *s6dns_analyze_rtypetable = s6dns_analyze_rtypetable_array ; diff --git a/src/libs6dns/s6dns_constants_error.c b/src/libs6dns/s6dns_constants_error.c new file mode 100644 index 0000000..d5e4bcb --- /dev/null +++ b/src/libs6dns/s6dns_constants_error.c @@ -0,0 +1,23 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <s6-dns/s6dns-constants.h> + +static s6dns_constants_error_message_t const array[] = +{ + { ENETUNREACH, "no available DNS server" }, + { EBADMSG, "server did not understand query" }, + { EBUSY, "server failure" }, + { ENOENT, "no such domain" }, + { ENOTSUP, "not implemented in server" }, + { ECONNREFUSED, "server refused" }, + { EIO, "unknown network error" }, + { EAGAIN, "query still processing" }, + { ETIMEDOUT, "query timed out" }, + { EPROTO, "malformed packet" }, + { EDOM, "internal error (please submit a bug-report)" }, + { -1, "unknown error" } +} ; + +s6dns_constants_error_message_t const *const s6dns_constants_error = array ; diff --git a/src/libs6dns/s6dns_constants_error_str.c b/src/libs6dns/s6dns_constants_error_str.c new file mode 100644 index 0000000..9dda1a7 --- /dev/null +++ b/src/libs6dns/s6dns_constants_error_str.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include <skalibs/error.h> +#include <s6-dns/s6dns-constants.h> + +char const *s6dns_constants_error_str (int e) +{ + s6dns_constants_error_message_t *p = s6dns_constants_error ; + while ((p->num != e) && (p->num != -1)) p++ ; + return p->num == -1 ? error_str(e) : p->string ; +} diff --git a/src/libs6dns/s6dns_debug_dumpdt_post_recv.c b/src/libs6dns/s6dns_debug_dumpdt_post_recv.c new file mode 100644 index 0000000..5680489 --- /dev/null +++ b/src/libs6dns/s6dns_debug_dumpdt_post_recv.c @@ -0,0 +1,14 @@ +/* ISC license */ + +#include <skalibs/genwrite.h> +#include <s6-dns/s6dns-engine.h> +#include <s6-dns/s6dns-debug.h> + +int s6dns_debug_dumpdt_post_recv (s6dns_engine_t const *dt, void *data) +{ + genwrite_t *gp = data ; + (void)dt ; + if ((*gp->put)(gp->target, "Received a packet\n", 19) < 19) return 0 ; + if ((*gp->put)(gp->target, "\n", 1) < 1) return 0 ; + return (*gp->flush)(gp->target) ; +} diff --git a/src/libs6dns/s6dns_debug_dumpdt_post_send.c b/src/libs6dns/s6dns_debug_dumpdt_post_send.c new file mode 100644 index 0000000..e41d595 --- /dev/null +++ b/src/libs6dns/s6dns_debug_dumpdt_post_send.c @@ -0,0 +1,30 @@ +/* ISC license */ + +#include <skalibs/uint16.h> +#include <skalibs/djbtime.h> +#include <skalibs/genwrite.h> +#include <s6-dns/s6dns-engine.h> +#include <s6-dns/s6dns-debug.h> + +int s6dns_debug_dumpdt_post_send (s6dns_engine_t const *dt, void *data) +{ + genwrite_t *gp = data ; + char buf[LOCALTMN_FMT] ; + unsigned int len ; + if ((*gp->put)(gp->target, "Sent query ", 11) < 11) return 0 ; + { + uint16 id ; + uint16_unpack_big(dt->sa.s + 2, &id) ; + len = uint16_fmt(buf, id) ; + } + if ((*gp->put)(gp->target, buf, len) < (int)len) return 0 ; + if ((*gp->put)(gp->target, " - next recv deadline is ", 25) < 25) return 0 ; + { + localtmn_t l ; + if (!localtmn_from_tain(&l, &dt->localdeadline, 0)) return 0 ; + len = localtmn_fmt(buf, &l) ; + } + if ((*gp->put)(gp->target, buf, len) < (int)len) return 0 ; + if ((*gp->put)(gp->target, "\n\n", 2) < 2) return 0 ; + return (*gp->flush)(gp->target) ; +} diff --git a/src/libs6dns/s6dns_debug_dumpdt_pre_send.c b/src/libs6dns/s6dns_debug_dumpdt_pre_send.c new file mode 100644 index 0000000..df8131d --- /dev/null +++ b/src/libs6dns/s6dns_debug_dumpdt_pre_send.c @@ -0,0 +1,59 @@ +/* ISC license */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/fmtscan.h> +#include <skalibs/tai.h> +#include <skalibs/djbtime.h> +#include <skalibs/genwrite.h> +#include <skalibs/ip46.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-ip46.h> +#include <s6-dns/s6dns-engine.h> +#include <s6-dns/s6dns-analyze.h> +#include <s6-dns/s6dns-debug.h> + +#ifdef SKALIBS_IPV6_ENABLED +# define s6dns_ipfmt(buf, ip, is6) ((is6) ? ip6_fmt(buf, ip) : ip4_fmt(buf, ip)) +#else +# define s6dns_ipfmt(buf, ip, is6) ip4_fmt(buf, ip) +#endif + +int s6dns_debug_dumpdt_pre_send (s6dns_engine_t const *dt, void *data) +{ + genwrite_t *gp = data ; + char buf[LOCALTMN_FMT] ; + unsigned int len ; + if ((*gp->put)(gp->target, "Preparing to send via ", 22) < 22) return 0 ; + if ((*gp->put)(gp->target, dt->flagtcp ? "TCP" : "UDP", 3) < 3) return 0 ; + if ((*gp->put)(gp->target, " to ", 4) < 4) return 0 ; + len = dt->sa.s[4] & 1 ; + if ((*gp->put)(gp->target, len ? "cache" : "server", len ? 5 : 6) < (len ? 5 : 6)) return 0 ; + if ((*gp->put)(gp->target, " ", 1) < 1) return 0 ; + len = s6dns_ipfmt(buf, s6dns_ip46list_ip(&dt->servers, dt->curserver), s6dns_ip46list_is6(&dt->servers, dt->curserver)) ; + if ((*gp->put)(gp->target, buf, len) < (int)len) return 0 ; + if ((*gp->put)(gp->target, " with deadline ", 15) < 15) return 0 ; + { + localtmn_t l ; + if (!localtmn_from_tain(&l, &dt->localdeadline, 0)) + { + if (errno != EOVERFLOW) return 0 ; + byte_copy(buf, 10, "\"infinite\"") ; len = 10 ; + } + else len = localtmn_fmt(buf, &l) ; + } + if ((*gp->put)(gp->target, buf, len) < (int)len) return 0 ; + if ((*gp->put)(gp->target, ", ", 2) < 2) return 0 ; + if (dt->flagstrict && (*gp->put)(gp->target, "strict, ", 8) < 8) return 0 ; + if ((*gp->put)(gp->target, "query id ", 9) < 9) return 0 ; + { + uint16 id ; + uint16_unpack_big(dt->sa.s + 2, &id) ; + len = uint16_fmt(buf, id) ; + } + if ((*gp->put)(gp->target, buf, len) < (int)len) return 0 ; + if ((*gp->put)(gp->target, ":\n", 2) < 2) return 0 ; + if (!s6dns_analyze_packet(gp, dt->sa.s + 2, dt->querylen - 2, 1)) return 0 ; + if ((*gp->put)(gp->target, "\n", 1) < 1) return 0 ; + return (*gp->flush)(gp->target) ; +} diff --git a/src/libs6dns/s6dns_debug_dumpdt_stderr.c b/src/libs6dns/s6dns_debug_dumpdt_stderr.c new file mode 100644 index 0000000..46bdbea --- /dev/null +++ b/src/libs6dns/s6dns_debug_dumpdt_stderr.c @@ -0,0 +1,7 @@ +/* ISC license */ + +#include <skalibs/genwrite.h> +#include <s6-dns/s6dns-engine.h> +#include <s6-dns/s6dns-debug.h> + +s6dns_debughook_t const s6dns_debug_dumpdt_stderr = S6DNS_DEBUG_DUMPDT_INIT((void *)&genwrite_stderr) ; diff --git a/src/libs6dns/s6dns_debug_dumpdt_stdout.c b/src/libs6dns/s6dns_debug_dumpdt_stdout.c new file mode 100644 index 0000000..9862549 --- /dev/null +++ b/src/libs6dns/s6dns_debug_dumpdt_stdout.c @@ -0,0 +1,7 @@ +/* ISC license */ + +#include <skalibs/genwrite.h> +#include <s6-dns/s6dns-engine.h> +#include <s6-dns/s6dns-debug.h> + +s6dns_debughook_t const s6dns_debug_dumpdt_stdout = S6DNS_DEBUG_DUMPDT_INIT((void *)&genwrite_stdout) ; diff --git a/src/libs6dns/s6dns_debughook_zero.c b/src/libs6dns/s6dns_debughook_zero.c new file mode 100644 index 0000000..f3006b2 --- /dev/null +++ b/src/libs6dns/s6dns_debughook_zero.c @@ -0,0 +1,5 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-engine.h> + +s6dns_debughook_t const s6dns_debughook_zero = S6DNS_DEBUGHOOK_ZERO ; diff --git a/src/libs6dns/s6dns_domain_arpafromip4.c b/src/libs6dns/s6dns_domain_arpafromip4.c new file mode 100644 index 0000000..d77938f --- /dev/null +++ b/src/libs6dns/s6dns_domain_arpafromip4.c @@ -0,0 +1,19 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/uint.h> +#include <s6-dns/s6dns-domain.h> + +void s6dns_domain_arpafromip4 (s6dns_domain_t *d, char const *ip) +{ + register unsigned int i = 0 ; + d->len = 0 ; + d->s[d->len++] = '.' ; + for (; i < 4 ; i++) + { + register unsigned int u = ((unsigned char *)ip)[3-i] ; + d->len += uint_fmt(d->s + d->len, u) ; + d->s[d->len++] = '.' ; + } + byte_copy(d->s + d->len, 13, "in-addr.arpa.") ; d->len += 13 ; +} diff --git a/src/libs6dns/s6dns_domain_arpafromip6.c b/src/libs6dns/s6dns_domain_arpafromip6.c new file mode 100644 index 0000000..3b58127 --- /dev/null +++ b/src/libs6dns/s6dns_domain_arpafromip6.c @@ -0,0 +1,21 @@ +/* ISC license. */ + +#include <skalibs/bytestr.h> +#include <skalibs/fmtscan.h> +#include <s6-dns/s6dns-domain.h> + +void s6dns_domain_arpafromip6 (s6dns_domain_t *d, char const *ip6, unsigned int mask) +{ + register unsigned int i ; + if (mask > 128) mask = 128 ; + mask = mask ? 1 + ((mask-1) >> 2) : 0 ; + d->len = 0 ; + d->s[d->len++] = '.' ; + for (i = 32 - mask ; i < 32 ; i++) + { + unsigned char c = ip6[15-(i>>1)] ; + d->s[d->len++] = fmtscan_asc((i & 1) ? (c >> 4) : (c & 15)) ; + d->s[d->len++] = '.' ; + } + byte_copy(d->s + d->len, 9, "ip6.arpa.") ; d->len += 9 ; +} diff --git a/src/libs6dns/s6dns_domain_decode.c b/src/libs6dns/s6dns_domain_decode.c new file mode 100644 index 0000000..db4ccf5 --- /dev/null +++ b/src/libs6dns/s6dns_domain_decode.c @@ -0,0 +1,30 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/bytestr.h> +#include <s6-dns/s6dns-domain.h> + +static inline unsigned int s6dns_domain_label_decode (char *s, unsigned int max) +{ + unsigned int len = *(unsigned char *)s ; + if ((len > 63) || (len >= max)) return (errno = EPROTO, 0) ; + *s = '.' ; + case_lowerb(s+1, len) ; + return len + 1 ; +} + +int s6dns_domain_decode (s6dns_domain_t *d) +{ + unsigned int max = 255 ; + unsigned int pos = 0 ; + for (;;) + { + register unsigned int r = s6dns_domain_label_decode(d->s + pos, max - pos) ; + if (!r) return 0 ; + pos += r ; + if (r == 1) break ; + } + d->len = pos ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_domain_encode.c b/src/libs6dns/s6dns_domain_encode.c new file mode 100644 index 0000000..61a790d --- /dev/null +++ b/src/libs6dns/s6dns_domain_encode.c @@ -0,0 +1,21 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/bytestr.h> +#include <s6-dns/s6dns-domain.h> + +int s6dns_domain_encode (s6dns_domain_t *d) +{ + register char *s = d->s ; + register unsigned int len = d->len ; + if (!d->len || (*s != '.')) return (errno = EINVAL, 0) ; + while (len > 1) + { + register unsigned int n = byte_chr(s + 1, len - 1, '.') ; + if (n > 63) return (errno = EINVAL, 0) ; + *s = n++ ; s += n ; len -= n ; + } + if (!len) return (errno = EINVAL, 0) ; + *s = 0 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_domain_encodelist.c b/src/libs6dns/s6dns_domain_encodelist.c new file mode 100644 index 0000000..23b4570 --- /dev/null +++ b/src/libs6dns/s6dns_domain_encodelist.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-domain.h> + +unsigned int s6dns_domain_encodelist (s6dns_domain_t *list, unsigned int n) +{ + register unsigned int i = 0 ; + for (; i < n ; i++) + if (!s6dns_domain_encode(list + i)) break ; + return i ; +} diff --git a/src/libs6dns/s6dns_domain_fromstring.c b/src/libs6dns/s6dns_domain_fromstring.c new file mode 100644 index 0000000..9346e24 --- /dev/null +++ b/src/libs6dns/s6dns_domain_fromstring.c @@ -0,0 +1,30 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/bytestr.h> +#include <s6-dns/s6dns-domain.h> + +int s6dns_domain_fromstring (s6dns_domain_t *d, char const *s, unsigned int len) +{ + register unsigned int j = 1 ; + register unsigned int i = 0 ; + register unsigned int lastdot = 0 ; + d->s[0] = '.' ; + for (; i < len ; i++) + { + if (lastdot) + { + if ((j >= 255) || (lastdot++ >= 64)) return (errno = ENAMETOOLONG, 0) ; + d->s[j++] = s[i] ; + } + if (s[i] == '.') lastdot = 0 ; + else if (!lastdot) + { + i-- ; + lastdot = 1 ; + } + } + case_lowerb(d->s + 1, j-1) ; + d->len = j ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_domain_fromstring_noqualify_encode.c b/src/libs6dns/s6dns_domain_fromstring_noqualify_encode.c new file mode 100644 index 0000000..a12f979 --- /dev/null +++ b/src/libs6dns/s6dns_domain_fromstring_noqualify_encode.c @@ -0,0 +1,10 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-domain.h> + +int s6dns_domain_fromstring_noqualify_encode (s6dns_domain_t *d, char const *name, unsigned int len) +{ + return s6dns_domain_fromstring(d, name, len) + && s6dns_domain_noqualify(d) + && s6dns_domain_encode(d) ; +} diff --git a/src/libs6dns/s6dns_domain_fromstring_qualify_encode.c b/src/libs6dns/s6dns_domain_fromstring_qualify_encode.c new file mode 100644 index 0000000..dbdea02 --- /dev/null +++ b/src/libs6dns/s6dns_domain_fromstring_qualify_encode.c @@ -0,0 +1,10 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-domain.h> + +unsigned int s6dns_domain_fromstring_qualify_encode (s6dns_domain_t *list, char const *name, unsigned int len, char const *rules, unsigned int rulesnum) +{ + s6dns_domain_t d ; + if (!s6dns_domain_fromstring(&d, name, len)) return 0 ; + return s6dns_domain_encodelist(list, s6dns_domain_qualify(list, &d, rules, rulesnum)) ; +} diff --git a/src/libs6dns/s6dns_domain_noqualify.c b/src/libs6dns/s6dns_domain_noqualify.c new file mode 100644 index 0000000..4f91171 --- /dev/null +++ b/src/libs6dns/s6dns_domain_noqualify.c @@ -0,0 +1,14 @@ +/* ISC license. */ + +#include <errno.h> +#include <s6-dns/s6dns-domain.h> + +int s6dns_domain_noqualify (s6dns_domain_t *d) +{ + if (d->s[d->len-1] != '.') + { + if (d->len == 255) return (errno = ENAMETOOLONG, 0) ; + d->s[d->len++] = '.' ; + } + return 1 ; +} diff --git a/src/libs6dns/s6dns_domain_qualify.c b/src/libs6dns/s6dns_domain_qualify.c new file mode 100644 index 0000000..6194ab5 --- /dev/null +++ b/src/libs6dns/s6dns_domain_qualify.c @@ -0,0 +1,30 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/bytestr.h> +#include <s6-dns/s6dns-domain.h> + +unsigned int s6dns_domain_qualify (s6dns_domain_t *list, s6dns_domain_t const *d, char const *rules, unsigned int rulesnum) +{ + if (!d->len) return (errno = EINVAL, 0) ; + if (d->s[d->len - 1] == '.') + { + list[0] = *d ; + return 1 ; + } + else + { + register unsigned int i = 0 ; + for (; i < rulesnum ; i++) + { + unsigned int n = str_len(rules) ; + if (d->len + n >= 254) return (errno = ENAMETOOLONG, 0) ; + list[i] = *d ; + list[i].s[d->len] = '.' ; + byte_copy(list[i].s + d->len + 1, n, rules) ; + list[i].len += n+1 ; + rules += n+1 ; + } + return i ; + } +} diff --git a/src/libs6dns/s6dns_domain_tostring.c b/src/libs6dns/s6dns_domain_tostring.c new file mode 100644 index 0000000..ff72893 --- /dev/null +++ b/src/libs6dns/s6dns_domain_tostring.c @@ -0,0 +1,21 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/bytestr.h> +#include <s6-dns/s6dns-domain.h> + +unsigned int s6dns_domain_tostring (char *s, unsigned int max, s6dns_domain_t const *d) +{ + if ((unsigned int)d->len + 1 > max) return (errno = ENAMETOOLONG, 0) ; + if (!d->len || (d->s[0] != '.')) return (errno = EINVAL, 0) ; + if (d->len == 1) + { + s[0] = '.' ; + return 1 ; + } + else + { + byte_copy(s, d->len - 1, d->s + 1) ; + return d->len - 1 ; + } +} diff --git a/src/libs6dns/s6dns_engine.c b/src/libs6dns/s6dns_engine.c new file mode 100644 index 0000000..4145ef7 --- /dev/null +++ b/src/libs6dns/s6dns_engine.c @@ -0,0 +1,372 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/bytestr.h> +#include <skalibs/error.h> +#include <skalibs/tai.h> +#include <skalibs/stralloc.h> +#include <skalibs/mininetstring.h> +#include <skalibs/socket.h> +#include <skalibs/djbunix.h> +#include <skalibs/ip46.h> +#include <skalibs/random.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-message-internal.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-engine.h> + + + /* Utility functions */ + +static inline int qdomain_diff (char const *s1, unsigned int n1, char const *s2, unsigned int n2) +{ + return (n1 < n2) ? -1 : (n1 > n2) ? 1 : case_diffb(s1, n1, s2) ; +} + +static int relevant (char const *q, unsigned int qlen, char const *ans, unsigned int anslen, int strict) +{ + { + s6dns_message_header_t h ; + uint16 id ; + s6dns_message_header_unpack(ans, &h) ; + if (!h.qr || h.opcode || h.z || (h.counts.qd != 1)) return 0 ; + if (h.rd != (q[2] & 1)) return 0 ; + if (strict && !h.aa && !(q[2] & 1)) return 0 ; + uint16_unpack_big(q, &id) ; + if (id != h.id) return 0 ; + } + { + char buf[255] ; + unsigned int pos = 12 ; + unsigned int n = s6dns_message_get_domain_internal(buf, 255, ans, anslen, &pos) ; + if (!n) return -1 ; + if (pos + 4 > anslen) return (errno = EPROTO, -1) ; + if (qdomain_diff(buf, n, q + 12, qlen - 16)) return 0 ; + if (byte_diff(q + qlen - 4, 4, ans + pos)) return 0 ; + } + return 1 ; +} + + + /* Network core functions: transport-dependent */ + +#ifdef SKALIBS_IPV6_ENABLED +# define socketbind46(fd, ip, port, flag) ((flag) ? socket_bind6(fd, ip, port) : socket_bind4(fd, ip, port)) +# define socketudp46(flag) ((flag) ? socket_udp6() : socket_udp4()) +# define sockettcp46(flag) ((flag) ? socket_tcp6() : socket_tcp4()) +# define socketconnect46(fd, ip, port, flag) ((flag) ? socket_connect6(fd, ip, port) : socket_connect4(fd, ip, port)) +# define S6DNS_ENGINE_LOCAL0 IP6_ANY +#else +# define socketbind46(fd, ip, port, flag) ((void)(flag), socket_bind4(fd, ip, port)) +# define socketudp46(flag) socket_udp4() +# define sockettcp46(flag) socket_tcp4() +# define socketconnect46(fd, ip, port, flag) socket_connect4(fd, ip, port) +# define S6DNS_ENGINE_LOCAL0 "\0\0\0" +#endif + +static int randombind (int fd, int flag) +{ + register unsigned int i = 0 ; + for (; i < 10 ; i++) + if (socketbind46(fd, S6DNS_ENGINE_LOCAL0, 1025 + badrandom_int(64510), flag) >= 0) return 1 ; + return (socketbind46(fd, S6DNS_ENGINE_LOCAL0, 0, flag) >= 0) ; +} + +static int thisudp (s6dns_engine_t *dt, tain_t const *stamp) +{ + for (;; dt->curserver++) + { + if (dt->curserver >= S6DNS_MAX_SERVERS) + { + dt->curserver = 0 ; + if (++dt->protostate >= 4) return -1 ; + } + if (byte_diff(s6dns_ip46list_ip(&dt->servers, dt->curserver), SKALIBS_IP_SIZE, S6DNS_ENGINE_LOCAL0)) break ; + } + if (badrandom_string(dt->sa.s + 2, 2) < 2) return 0 ; /* random query id */ + dt->fd = socketudp46(s6dns_ip46list_is6(&dt->servers, dt->curserver)) ; + if (dt->fd < 0) return 0 ; + if (!randombind(dt->fd, s6dns_ip46list_is6(&dt->servers, dt->curserver))) goto err ; /* random source port */ + if ((socketconnect46(dt->fd, s6dns_ip46list_ip(&dt->servers, dt->curserver), 53, s6dns_ip46list_is6(&dt->servers, dt->curserver)) < 0) + && (errno != EINPROGRESS)) goto err ; + tain_add(&dt->localdeadline, stamp, &tain_infinite_relative) ; + dt->flagreading = 0 ; + dt->flagwriting = 1 ; + if (dt->debughook && dt->debughook->pre_send) (*dt->debughook->pre_send)(dt, dt->debughook->external) ; + return 1 ; + err: + { + register int e = errno ; + fd_close(dt->fd) ; dt->fd = -1 ; + errno = e ; + } + return 0 ; +} + +static int thistcp (s6dns_engine_t *dt, tain_t const *stamp) +{ + for (; dt->curserver < S6DNS_MAX_SERVERS ; dt->curserver++) + if (byte_diff(s6dns_ip46list_ip(&dt->servers, dt->curserver), SKALIBS_IP_SIZE, S6DNS_ENGINE_LOCAL0)) break ; + if (dt->curserver >= S6DNS_MAX_SERVERS) return -1 ; + if (badrandom_string(dt->sa.s + 2, 2) < 2) return 0 ; /* random query id */ + dt->fd = sockettcp46(s6dns_ip46list_is6(&dt->servers, dt->curserver)) ; + if (dt->fd < 0) return 0 ; + if (!randombind(dt->fd, s6dns_ip46list_is6(&dt->servers, dt->curserver))) goto err ; /* random source port */ + if ((socketconnect46(dt->fd, s6dns_ip46list_ip(&dt->servers, dt->curserver), 53, s6dns_ip46list_is6(&dt->servers, dt->curserver)) < 0) + && (errno != EINPROGRESS)) goto err ; + tain_addsec(&dt->localdeadline, stamp, 10) ; + dt->protostate = 0 ; + dt->flagtcp = dt->flagconnecting = dt->flagwriting = 1 ; + dt->flagreading = 0 ; + if (dt->debughook && dt->debughook->pre_send) (*dt->debughook->pre_send)(dt, dt->debughook->external) ; + return 1 ; + err: + { + register int e = errno ; + fd_close(dt->fd) ; dt->fd = -1 ; + errno = e ; + } + return 0 ; +} + + + /* all the rest is transport-agnostic */ + +static int s6dns_engine_prepare (s6dns_engine_t *dt, tain_t const *stamp, int istcp) +{ + for (;; dt->curserver++) + switch (istcp ? thistcp(dt, stamp) : thisudp(dt, stamp)) + { + case -1 : return (errno = ENETUNREACH, 0) ; + case 0 : break ; + case 1 : return 1 ; + default : return (errno = EDOM, 0) ; /* can't happen */ + } +} + +static void prepare_next (s6dns_engine_t *dt, tain_t const *stamp, int istcp) +{ + if (!error_isagain(errno)) + { + fd_close(dt->fd) ; + dt->curserver++ ; + if (s6dns_engine_prepare(dt, stamp, istcp)) errno = EAGAIN ; + } +} + +static int s6dns_engine_write_udp (s6dns_engine_t *dt, tain_t const *stamp) +{ + static unsigned int const s6dns_engine_udp_timeouts[4] = { 1, 3, 11, 45 } ; + if (fd_send(dt->fd, dt->sa.s + 2, dt->querylen - 2, 0) < (int)(dt->querylen - 2)) + return (prepare_next(dt, stamp, 0), 0) ; + tain_addsec(&dt->localdeadline, stamp, s6dns_engine_udp_timeouts[dt->protostate]) ; + dt->flagwriting = 0 ; + dt->flagreading = 1 ; + if (dt->debughook && dt->debughook->post_send) (*dt->debughook->post_send)(dt, dt->debughook->external) ; + return (errno = EAGAIN, 1) ; +} + +static int s6dns_engine_write_tcp (s6dns_engine_t *dt, tain_t const *stamp) +{ + unsigned int r ; + r = allwrite(dt->fd, dt->sa.s + dt->protostate, dt->querylen - dt->protostate) ; + dt->protostate += r ; + if (r) dt->flagconnecting = 0 ; + if (dt->protostate < dt->sa.len) + { + if ((errno == ECONNRESET) && dt->flagconnecting) errno = EAGAIN ; + prepare_next(dt, stamp, 1) ; + return 0 ; + } + dt->protostate = 0 ; + tain_addsec(&dt->localdeadline, stamp, 10) ; + dt->flagwriting = 0 ; + dt->flagreading = 1 ; + if (dt->debughook && dt->debughook->post_send) (*dt->debughook->post_send)(dt, dt->debughook->external) ; + return (errno = EAGAIN, 1) ; +} + +static int s6dns_engine_read_udp (s6dns_engine_t *dt, tain_t const *stamp) +{ + s6dns_message_header_t h ; + char buf[513] ; + register int r = fd_recv(dt->fd, buf, 513, 0) ; + if (r < 0) return (prepare_next(dt, stamp, 0), 0) ; + if ((r > 512) || (r < 12)) return (errno = EAGAIN, 0) ; + switch (relevant(dt->sa.s + 2, dt->querylen - 2, buf, r, dt->flagstrict)) + { + case -1 : if (!dt->flagstrict) prepare_next(dt, stamp, 0) ; return 0 ; + case 0 : return (errno = EAGAIN, 0) ; + case 1 : break ; + default : return (errno = EDOM, 0) ; /* can't happen */ + } + if (dt->debughook && dt->debughook->post_recv) + { + if (!stralloc_catb(&dt->sa, buf, r)) return 0 ; + (*dt->debughook->post_recv)(dt, dt->debughook->external) ; + dt->sa.len = dt->querylen ; + } + s6dns_message_header_unpack(buf, &h) ; + if (h.tc) + { + fd_close(dt->fd) ; + dt->curserver = 0 ; + dt->protostate = 0 ; + if (s6dns_engine_prepare(dt, stamp, 1)) errno = EAGAIN ; + return 0 ; + } + switch (h.rcode) + { + case 0 : case 3 : break ; /* normal operation */ + case 1 : case 4 : case 5 : + byte_zero(s6dns_ip46list_ip(&dt->servers, dt->curserver), SKALIBS_IP_SIZE) ; /* do not query it again */ + default : prepare_next(dt, stamp, 0) ; return 0 ; + } + if (!stralloc_copyb(&dt->sa, buf, r)) + { + register int e = errno ; + fd_close(dt->fd) ; dt->fd = -1 ; + errno = e ; + return 0 ; + } + dt->querylen = 0 ; + fd_close(dt->fd) ; dt->fd = -1 ; + dt->flagreading = 0 ; + return 1 ; +} + +static int s6dns_engine_read_tcp (s6dns_engine_t *dt, tain_t const *stamp) +{ + register int r = sanitize_read(mininetstring_read(dt->fd, &dt->sa, &dt->protostate)) ; + if (r < 0) return (prepare_next(dt, stamp, 1), 0) ; + else if (!r) return (errno = EAGAIN, 0) ; + else if ((dt->sa.len - dt->querylen) < 12) + { + errno = EPROTO ; + goto badanswer ; + } + else + { + s6dns_message_header_t h ; + switch (relevant(dt->sa.s + 2, dt->querylen - 2, dt->sa.s + dt->querylen, dt->sa.len - dt->querylen, dt->flagstrict)) + { + case -1 : if (dt->flagstrict) { dt->sa.len = dt->querylen ; return 0 ; } + case 0 : goto badanswer ; + case 1 : break ; + default : dt->sa.len = dt->querylen ; return (errno = EDOM, 0) ; /* can't happen */ + } + if (dt->debughook && dt->debughook->post_recv) (*dt->debughook->post_recv)(dt, dt->debughook->external) ; + s6dns_message_header_unpack(dt->sa.s + dt->querylen, &h) ; + if (h.tc) goto badanswer ; + switch (h.rcode) + { + case 0 : case 3 : break ; /* normal operation */ + case 1 : case 4 : case 5 : + byte_zero(s6dns_ip46list_ip(&dt->servers, dt->curserver), SKALIBS_IP_SIZE) ; /* do not query it again */ + default : goto badanswer ; + } + fd_close(dt->fd) ; dt->fd = -1 ; + dt->flagreading = 0 ; + return 1 ; + } + badanswer: + dt->sa.len = dt->querylen ; + prepare_next(dt, stamp, 1) ; + return 0 ; +} + + +void s6dns_engine_recycle (s6dns_engine_t *dt) +{ + dt->sa.len = 0 ; + dt->querylen = 0 ; + byte_zero(&dt->servers, sizeof(s6dns_ip46list_t)) ; + if (dt->fd >= 0) + { + register int e = errno ; + fd_close(dt->fd) ; + dt->fd = -1 ; + errno = e ; + } + dt->status = ECONNABORTED ; + dt->flagstrict = dt->flagtcp = dt->flagconnecting = dt->flagreading = dt->flagwriting = 0 ; +} + +int s6dns_engine_timeout (s6dns_engine_t *dt, tain_t const *stamp) +{ + if (!error_isagain(dt->status)) return (errno = EINVAL, -1) ; + else if (tain_less(&dt->deadline, stamp)) goto yes ; + else if (!tain_less(&dt->localdeadline, stamp)) return 0 ; + else if (dt->flagwriting) goto yes ; + else if (!dt->flagreading) return 0 ; + fd_close(dt->fd) ; + dt->curserver++ ; + if (!s6dns_engine_prepare(dt, stamp, dt->flagtcp)) + { + s6dns_engine_recycle(dt) ; + dt->status = errno ; + return -1 ; + } + return 0 ; + yes: + s6dns_engine_recycle(dt) ; + dt->status = ETIMEDOUT ; + return 1 ; +} + +int s6dns_engine_event (s6dns_engine_t *dt, tain_t const *stamp) +{ + if (!error_isagain(dt->status)) return (errno = EINVAL, -1) ; + if (dt->flagwriting) + dt->flagtcp ? s6dns_engine_write_tcp(dt, stamp) : s6dns_engine_write_udp(dt, stamp) ; + else if (dt->flagreading) + { + if ((dt->flagtcp) ? s6dns_engine_read_tcp(dt, stamp) : s6dns_engine_read_udp(dt, stamp)) + { + dt->status = 0 ; + return 1 ; + } + } + else return (errno = EINVAL, -1) ; + if (error_isagain(errno)) return 0 ; + s6dns_engine_recycle(dt) ; + dt->status = errno ; + return -1 ; +} + +int s6dns_engine_init_r (s6dns_engine_t *dt, s6dns_ip46list_t const *servers, uint32 options, char const *q, unsigned int qlen, uint16 qtype, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t const *stamp) +{ + s6dns_message_header_t h = S6DNS_MESSAGE_HEADER_ZERO ; + if (!stralloc_ready(&dt->sa, qlen + 18)) return 0 ; + dt->deadline = *deadline ; + dt->localdeadline = *stamp ; + dt->querylen = qlen + 18 ; + dt->sa.len = dt->querylen ; + dt->servers = *servers ; + dt->debughook = dbh ; + dt->status = EAGAIN ; + dt->flagconnecting = dt->flagreading = dt->flagwriting = 0 ; + dt->flagstrict = !!(options & S6DNS_O_STRICT) ; + h.rd = !!(options & S6DNS_O_RECURSIVE) ; + h.counts.qd = 1 ; + uint16_pack_big(dt->sa.s, qlen + 16) ; + s6dns_message_header_pack(dt->sa.s + 2, &h) ; + byte_copy(dt->sa.s + 14, qlen, q) ; + uint16_pack_big(dt->sa.s + 14 + qlen, qtype) ; + uint16_pack_big(dt->sa.s + 16 + qlen, S6DNS_C_IN) ; + if (qlen > 496) dt->flagtcp = 1 ; + else + { + dt->flagtcp = 0 ; + dt->protostate = h.rd ; + } + if (!s6dns_engine_prepare(dt, stamp, dt->flagtcp)) + { + s6dns_engine_recycle(dt) ; + return 0 ; + } + return 1 ; +} diff --git a/src/libs6dns/s6dns_engine_free.c b/src/libs6dns/s6dns_engine_free.c new file mode 100644 index 0000000..cfee465 --- /dev/null +++ b/src/libs6dns/s6dns_engine_free.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include <skalibs/stralloc.h> +#include <s6-dns/s6dns-engine.h> + +void s6dns_engine_free (s6dns_engine_t *dt) +{ + s6dns_engine_recycle(dt) ; + stralloc_free(&dt->sa) ; + *dt = s6dns_engine_zero ; +} diff --git a/src/libs6dns/s6dns_engine_freen.c b/src/libs6dns/s6dns_engine_freen.c new file mode 100644 index 0000000..10dd47e --- /dev/null +++ b/src/libs6dns/s6dns_engine_freen.c @@ -0,0 +1,8 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-engine.h> + +void s6dns_engine_freen (s6dns_engine_t *dtl, unsigned int n) +{ + while (n--) s6dns_engine_free(dtl + n) ; +} diff --git a/src/libs6dns/s6dns_engine_here.c b/src/libs6dns/s6dns_engine_here.c new file mode 100644 index 0000000..17a5f43 --- /dev/null +++ b/src/libs6dns/s6dns_engine_here.c @@ -0,0 +1,7 @@ +/* ISC license. */ + +/* MT-unsafe */ + +#include <s6-dns/s6dns-engine.h> + +s6dns_engine_t s6dns_engine_here = S6DNS_ENGINE_ZERO ; diff --git a/src/libs6dns/s6dns_engine_nextdeadline.c b/src/libs6dns/s6dns_engine_nextdeadline.c new file mode 100644 index 0000000..09102c7 --- /dev/null +++ b/src/libs6dns/s6dns_engine_nextdeadline.c @@ -0,0 +1,10 @@ +/* ISC license. */ + +#include <skalibs/tai.h> +#include <s6-dns/s6dns-engine.h> + +void s6dns_engine_nextdeadline (s6dns_engine_t const *dt, tain_t *deadline) +{ + if (tain_less(&dt->deadline, deadline)) *deadline = dt->deadline ; + if (tain_less(&dt->localdeadline, deadline)) *deadline = dt->localdeadline ; +} diff --git a/src/libs6dns/s6dns_engine_zero.c b/src/libs6dns/s6dns_engine_zero.c new file mode 100644 index 0000000..ef3acaf --- /dev/null +++ b/src/libs6dns/s6dns_engine_zero.c @@ -0,0 +1,5 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-engine.h> + +s6dns_engine_t const s6dns_engine_zero = S6DNS_ENGINE_ZERO ; diff --git a/src/libs6dns/s6dns_fmt_domainlist.c b/src/libs6dns/s6dns_fmt_domainlist.c new file mode 100644 index 0000000..d53050a --- /dev/null +++ b/src/libs6dns/s6dns_fmt_domainlist.c @@ -0,0 +1,25 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/bytestr.h> +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-fmt.h> + +unsigned int s6dns_fmt_domainlist (char *s, unsigned int max, s6dns_domain_t const *list, unsigned int n, char const *delim, unsigned int delimlen) +{ + unsigned int len = 0 ; + register unsigned int i = 0 ; + for (; i < n ; i++) + { + register unsigned int r = s6dns_domain_tostring(s + len, max - len, list + i) ; + if (!r) return 0 ; + len += r ; + if (i+1 < n) + { + if (len + delimlen > max) return (errno = ENAMETOOLONG, 0) ; + byte_copy(s + len, delimlen, delim) ; + len += delimlen ; + } + } + return len ; +} diff --git a/src/libs6dns/s6dns_fmt_hinfo.c b/src/libs6dns/s6dns_fmt_hinfo.c new file mode 100644 index 0000000..8c1d7c4 --- /dev/null +++ b/src/libs6dns/s6dns_fmt_hinfo.c @@ -0,0 +1,15 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/bytestr.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-fmt.h> + +unsigned int s6dns_fmt_hinfo (char *s, unsigned int max, s6dns_message_rr_hinfo_t const *hinfo) +{ + if ((unsigned int)hinfo->cpu.len + 1 + (unsigned int)hinfo->os.len > max) return (errno = ENAMETOOLONG, 0) ; + byte_copy(s, hinfo->cpu.len, hinfo->cpu.s) ; + s[hinfo->cpu.len] = ' ' ; + byte_copy(s + hinfo->cpu.len + 1, hinfo->os.len, hinfo->os.s) ; + return hinfo->cpu.len + 1 + hinfo->os.len ; +} diff --git a/src/libs6dns/s6dns_fmt_mx.c b/src/libs6dns/s6dns_fmt_mx.c new file mode 100644 index 0000000..aba538b --- /dev/null +++ b/src/libs6dns/s6dns_fmt_mx.c @@ -0,0 +1,19 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <skalibs/bytestr.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-fmt.h> + +unsigned int s6dns_fmt_mx (char *s, unsigned int max, s6dns_message_rr_mx_t const *mx) +{ + char fmt[UINT16_FMT] ; + unsigned int len = uint16_fmt(fmt, mx->preference) ; + unsigned int r ; + if (len >= max) return 0 ; + fmt[len++] = ' ' ; + r = s6dns_domain_tostring(s + len, max - len, &mx->exchange) ; + if (!r) return 0 ; + byte_copy(s, len, fmt) ; + return len + r ; +} diff --git a/src/libs6dns/s6dns_fmt_soa.c b/src/libs6dns/s6dns_fmt_soa.c new file mode 100644 index 0000000..e066c6a --- /dev/null +++ b/src/libs6dns/s6dns_fmt_soa.c @@ -0,0 +1,44 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint32.h> +#include <skalibs/bytestr.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-fmt.h> + +unsigned int s6dns_fmt_soa (char *s, unsigned int max, s6dns_message_rr_soa_t const *soa) +{ + char fmt[UINT32_FMT] ; + unsigned int len = 0 ; + register unsigned int r = s6dns_domain_tostring(s + len, max - len, &soa->mname) ; + if (!r) return 0 ; + len += r ; + if (len >= max) return (errno = ENAMETOOLONG, 0) ; + s[len++] = ' ' ; + r = s6dns_domain_tostring(s + len, max - len, &soa->rname) ; + if (!r) return 0 ; + len += r ; + if (len >= max) return (errno = ENAMETOOLONG, 0) ; + s[len++] = ' ' ; + r = uint32_fmt(fmt, soa->serial) ; + if (len + r >= max) return (errno = ENAMETOOLONG, 0) ; + byte_copy(s + len, r, fmt) ; + len += r ; s[len++] = ' ' ; + r = uint32_fmt(fmt, soa->refresh) ; + if (len + r >= max) return (errno = ENAMETOOLONG, 0) ; + byte_copy(s + len, r, fmt) ; + len += r ; s[len++] = ' ' ; + r = uint32_fmt(fmt, soa->retry) ; + if (len + r >= max) return (errno = ENAMETOOLONG, 0) ; + byte_copy(s + len, r, fmt) ; + len += r ; s[len++] = ' ' ; + r = uint32_fmt(fmt, soa->expire) ; + if (len + r >= max) return (errno = ENAMETOOLONG, 0) ; + byte_copy(s + len, r, fmt) ; + len += r ; s[len++] = ' ' ; + r = uint32_fmt(fmt, soa->minimum) ; + if (len + r > max) return (errno = ENAMETOOLONG, 0) ; + byte_copy(s + len, r, fmt) ; + len += r ; + return len ; +} diff --git a/src/libs6dns/s6dns_fmt_srv.c b/src/libs6dns/s6dns_fmt_srv.c new file mode 100644 index 0000000..ad0944b --- /dev/null +++ b/src/libs6dns/s6dns_fmt_srv.c @@ -0,0 +1,29 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/bytestr.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-fmt.h> + +unsigned int s6dns_fmt_srv (char *s, unsigned int max, s6dns_message_rr_srv_t const *srv) +{ + char fmt[UINT16_FMT] ; + unsigned int len = 0 ; + register unsigned int r = uint16_fmt(fmt, srv->priority) ; + if (len + r >= max) return (errno = ENAMETOOLONG, 0) ; + byte_copy(s + len, r, fmt) ; + len += r ; s[len++] = ' ' ; + r = uint16_fmt(fmt, srv->weight) ; + if (len + r >= max) return (errno = ENAMETOOLONG, 0) ; + byte_copy(s + len, r, fmt) ; + len += r ; s[len++] = ' ' ; + r = uint16_fmt(fmt, srv->port) ; + if (len + r >= max) return (errno = ENAMETOOLONG, 0) ; + byte_copy(s + len, r, fmt) ; + len += r ; s[len++] = ' ' ; + r = s6dns_domain_tostring(s + len, max - len, &srv->target) ; + if (!r) return 0 ; + len += r ; + return len ; +} diff --git a/src/libs6dns/s6dns_message_counts_next.c b/src/libs6dns/s6dns_message_counts_next.c new file mode 100644 index 0000000..2006775 --- /dev/null +++ b/src/libs6dns/s6dns_message_counts_next.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-message.h> + +unsigned int s6dns_message_counts_next (s6dns_message_counts_t *counts) +{ + if (counts->qd) { counts->qd-- ; return 1 ; } + else if (counts->an) { counts->an-- ; return 2 ; } + else if (counts->ns) { counts->ns-- ; return 3 ; } + else if (counts->nr) { counts->nr-- ; return 4 ; } + else return 0 ; +} diff --git a/src/libs6dns/s6dns_message_counts_pack.c b/src/libs6dns/s6dns_message_counts_pack.c new file mode 100644 index 0000000..51c0a78 --- /dev/null +++ b/src/libs6dns/s6dns_message_counts_pack.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <s6-dns/s6dns-message.h> + +void s6dns_message_counts_pack (char *s, s6dns_message_counts_t const *counts) +{ + uint16_pack_big(s, counts->qd) ; + uint16_pack_big(s+2, counts->an) ; + uint16_pack_big(s+4, counts->ns) ; + uint16_pack_big(s+6, counts->nr) ; +} diff --git a/src/libs6dns/s6dns_message_counts_unpack.c b/src/libs6dns/s6dns_message_counts_unpack.c new file mode 100644 index 0000000..968e5eb --- /dev/null +++ b/src/libs6dns/s6dns_message_counts_unpack.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <s6-dns/s6dns-message.h> + +void s6dns_message_counts_unpack (char const *s, s6dns_message_counts_t *counts) +{ + uint16_unpack_big(s, &counts->qd) ; + uint16_unpack_big(s+2, &counts->an) ; + uint16_unpack_big(s+4, &counts->ns) ; + uint16_unpack_big(s+6, &counts->nr) ; +} diff --git a/src/libs6dns/s6dns_message_counts_zero.c b/src/libs6dns/s6dns_message_counts_zero.c new file mode 100644 index 0000000..b177aad --- /dev/null +++ b/src/libs6dns/s6dns_message_counts_zero.c @@ -0,0 +1,5 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-message.h> + +s6dns_message_counts_t const s6dns_message_counts_zero = S6DNS_MESSAGE_COUNTS_ZERO ; diff --git a/src/libs6dns/s6dns_message_get_domain.c b/src/libs6dns/s6dns_message_get_domain.c new file mode 100644 index 0000000..b51adb5 --- /dev/null +++ b/src/libs6dns/s6dns_message_get_domain.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-message-internal.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_get_domain (s6dns_domain_t *d, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + return s6dns_message_get_domain_internal(d->s, 255, packet, packetlen, pos) + && s6dns_domain_decode(d) ; +} diff --git a/src/libs6dns/s6dns_message_get_domain_internal.c b/src/libs6dns/s6dns_message_get_domain_internal.c new file mode 100644 index 0000000..357797d --- /dev/null +++ b/src/libs6dns/s6dns_message_get_domain_internal.c @@ -0,0 +1,47 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/bytestr.h> +#include "s6dns-message-internal.h" + +unsigned int s6dns_message_get_domain_internal (char *out, unsigned int outmax, char const *s, unsigned int len, unsigned int *pos) +{ + unsigned int w = 0 ; /* writing head */ + unsigned int r = *pos ; /* reading head */ + unsigned int jumps = 0 ; + register int hasjumped = 0 ; + for (;;) + { + unsigned char c ; + if (r >= len) return (errno = EPROTO, 0) ; + c = s[r] ; + if (c < 64) /* normal label */ + { + if (r + ++c > len) return (errno = EPROTO, 0) ; + if (out) + { + if (w + c > outmax) return (errno = ENAMETOOLONG, 0) ; + byte_copy(out + w, c, s + r) ; + } + w += c ; r += c ; if (!hasjumped) *pos += c ; + if (c == 1) break ; + } + else if (c >= 192) /* pointer */ + { + if (r + 1 >= len) return (errno = EPROTO, 0) ; + if (hasjumped) + { + if (++jumps > 1000) return (errno = EPROTO, 0) ; + } + else + { + *pos += 2 ; + hasjumped = 1 ; + } + r = (((unsigned int)c & 63) << 8) | (unsigned char)(s[r + 1]) ; + } + else return (errno = EPROTONOSUPPORT, 0) ; /* unsupported extension */ + } + return w ; +} diff --git a/src/libs6dns/s6dns_message_get_hinfo.c b/src/libs6dns/s6dns_message_get_hinfo.c new file mode 100644 index 0000000..c8ab821 --- /dev/null +++ b/src/libs6dns/s6dns_message_get_hinfo.c @@ -0,0 +1,9 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-message.h> + +int s6dns_message_get_hinfo (s6dns_message_rr_hinfo_t_ref hinfo, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + return s6dns_message_get_string(&hinfo->cpu, packet, packetlen, pos) + && s6dns_message_get_string(&hinfo->os, packet, packetlen, pos) ; +} diff --git a/src/libs6dns/s6dns_message_get_mx.c b/src/libs6dns/s6dns_message_get_mx.c new file mode 100644 index 0000000..6bca509 --- /dev/null +++ b/src/libs6dns/s6dns_message_get_mx.c @@ -0,0 +1,14 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/uint16.h> +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_get_mx (s6dns_message_rr_mx_t *mx, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + if (*pos + 3 > packetlen) return (errno = EPROTO, 0) ; + uint16_unpack_big(packet + *pos, &mx->preference) ; *pos += 2 ; + return s6dns_message_get_domain(&mx->exchange, packet, packetlen, pos) ; +} diff --git a/src/libs6dns/s6dns_message_get_soa.c b/src/libs6dns/s6dns_message_get_soa.c new file mode 100644 index 0000000..c766231 --- /dev/null +++ b/src/libs6dns/s6dns_message_get_soa.c @@ -0,0 +1,19 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/uint32.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_get_soa (s6dns_message_rr_soa_t *soa, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + if (!s6dns_message_get_domain(&soa->mname, packet, packetlen, pos)) return 0 ; + if (!s6dns_message_get_domain(&soa->rname, packet, packetlen, pos)) return 0 ; + if (*pos + 20 > packetlen) return (errno = EPROTO, 0) ; + uint32_unpack_big(packet + *pos, &soa->serial) ; *pos += 4 ; + uint32_unpack_big(packet + *pos, &soa->refresh) ; *pos += 4 ; + uint32_unpack_big(packet + *pos, &soa->retry) ; *pos += 4 ; + uint32_unpack_big(packet + *pos, &soa->expire) ; *pos += 4 ; + uint32_unpack_big(packet + *pos, &soa->minimum) ; *pos += 4 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_get_srv.c b/src/libs6dns/s6dns_message_get_srv.c new file mode 100644 index 0000000..13ecf13 --- /dev/null +++ b/src/libs6dns/s6dns_message_get_srv.c @@ -0,0 +1,15 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/uint16.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_get_srv (s6dns_message_rr_srv_t *srv, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + if (*pos + 7 > packetlen) return (errno = EPROTO, 0) ; + uint16_unpack_big(packet + *pos, &srv->priority) ; *pos += 2 ; + uint16_unpack_big(packet + *pos, &srv->weight) ; *pos += 2 ; + uint16_unpack_big(packet + *pos, &srv->port) ; *pos += 2 ; + return s6dns_message_get_domain(&srv->target, packet, packetlen, pos) ; +} diff --git a/src/libs6dns/s6dns_message_get_string.c b/src/libs6dns/s6dns_message_get_string.c new file mode 100644 index 0000000..706da39 --- /dev/null +++ b/src/libs6dns/s6dns_message_get_string.c @@ -0,0 +1,13 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-message.h> +#include "s6dns-message-internal.h" + +int s6dns_message_get_string (s6dns_domain_t *d, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + register int r = s6dns_message_get_string_internal(d->s, 255, packet, packetlen, pos) ; + if (r < 0) return 0 ; + d->len = r ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_get_string_internal.c b/src/libs6dns/s6dns_message_get_string_internal.c new file mode 100644 index 0000000..4f6eb0c --- /dev/null +++ b/src/libs6dns/s6dns_message_get_string_internal.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/bytestr.h> +#include "s6dns-message-internal.h" + +int s6dns_message_get_string_internal (char *s, unsigned int max, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + register unsigned char len = ((unsigned char const *)packet)[*pos] ; + if (*pos + len + 1 > packetlen) return (errno = EPROTO, -1) ; + if (len > max) return (errno = ENAMETOOLONG, -1) ; + byte_copy(s, len, packet + *pos + 1) ; + *pos += len + 1 ; + return (int)len ; +} diff --git a/src/libs6dns/s6dns_message_get_strings.c b/src/libs6dns/s6dns_message_get_strings.c new file mode 100644 index 0000000..161b554 --- /dev/null +++ b/src/libs6dns/s6dns_message_get_strings.c @@ -0,0 +1,17 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-message.h> +#include "s6dns-message-internal.h" + +int s6dns_message_get_strings (char *s, unsigned int rdlength, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + unsigned int max = rdlength, len = 0 ; + while (rdlength) + { + register unsigned int start = *pos ; + register int r = s6dns_message_get_string_internal(s + len, max - len, packet, packetlen, pos) ; + if (r < 0) return -1 ; + len += r ; rdlength -= *pos - start ; + } + return (int)len ; +} diff --git a/src/libs6dns/s6dns_message_header_pack.c b/src/libs6dns/s6dns_message_header_pack.c new file mode 100644 index 0000000..99ffa8a --- /dev/null +++ b/src/libs6dns/s6dns_message_header_pack.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <s6-dns/s6dns-message.h> + +void s6dns_message_header_pack (char *s, s6dns_message_header_t const *h) +{ + uint16_pack_big(s, h->id) ; + s[2] = (h->qr << 7) | (h->opcode << 3) | (h->aa << 2) | (h->tc << 1) | h->rd ; + s[3] = (h->z << 4) | h->rcode ; + s6dns_message_counts_pack(s+4, &h->counts) ; +} diff --git a/src/libs6dns/s6dns_message_header_unpack.c b/src/libs6dns/s6dns_message_header_unpack.c new file mode 100644 index 0000000..ae2b35c --- /dev/null +++ b/src/libs6dns/s6dns_message_header_unpack.c @@ -0,0 +1,18 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <s6-dns/s6dns-message.h> + +void s6dns_message_header_unpack (char const *s, s6dns_message_header_t *h) +{ + uint16_unpack_big(s, &h->id) ; + h->qr = s[2] & 0x8000U ? 1 : 0 ; + h->opcode = (s[2] >> 3) & 15 ; + h->aa = s[2] & 4 ? 1 : 0 ; + h->tc = s[2] & 2 ? 1 : 0 ; + h->rd = s[2] & 1 ; + h->ra = s[3] & 0x8000U ? 1 : 0 ; + h->z = (s[3] >> 4) & 7 ; + h->rcode = s[3] & 15 ; + s6dns_message_counts_unpack(s+4, &h->counts) ; +} diff --git a/src/libs6dns/s6dns_message_header_zero.c b/src/libs6dns/s6dns_message_header_zero.c new file mode 100644 index 0000000..5695e34 --- /dev/null +++ b/src/libs6dns/s6dns_message_header_zero.c @@ -0,0 +1,5 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-message.h> + +s6dns_message_header_t const s6dns_message_header_zero = S6DNS_MESSAGE_HEADER_ZERO ; diff --git a/src/libs6dns/s6dns_message_parse.c b/src/libs6dns/s6dns_message_parse.c new file mode 100644 index 0000000..f4af437 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse.c @@ -0,0 +1,37 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_parse (s6dns_message_header_t *h, char const *packet, unsigned int packetlen, s6dns_message_rr_func_t_ref f, void *data) +{ + s6dns_message_counts_t counts ; + unsigned int pos ; + unsigned int section ; + if (!s6dns_message_parse_init(h, &counts, packet, packetlen, &pos)) return 0 ; + switch (h->rcode) + { + case 0 : break ; + case 1 : return (errno = EBADMSG, 0) ; + case 2 : return (errno = EBUSY, 0) ; + case 3 : return (errno = ENOENT, 0) ; + case 4 : return (errno = ENOTSUP, 0) ; + case 5 : return (errno = ECONNREFUSED, 0) ; + default: return (errno = EIO, 0) ; + } + section = s6dns_message_parse_skipqd(&counts, packet, packetlen, &pos) ; + while (section) + { + s6dns_message_rr_t rr ; + if (!s6dns_message_parse_getrr(&rr, packet, packetlen, &pos)) return 0 ; + if (rr.rclass == S6DNS_C_IN) + { + register int r = (*f)(&rr, packet, packetlen, pos, section, data) ; + if (r < 1) return r ; + } + section = s6dns_message_parse_next(&counts, &rr, packet, packetlen, &pos) ; + } + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_parse_answer_a.c b/src/libs6dns/s6dns_message_parse_answer_a.c new file mode 100644 index 0000000..152b947 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_answer_a.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include <skalibs/stralloc.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_parse_answer_a (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *stuff) +{ + if ((section == 2) && (rr->rtype == S6DNS_T_A) && (rr->rdlength == 4)) + { + stralloc *data = stuff ; + if (!stralloc_catb(data, packet+pos, 4)) return -1 ; + } + (void)packetlen ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_parse_answer_aaaa.c b/src/libs6dns/s6dns_message_parse_answer_aaaa.c new file mode 100644 index 0000000..f1e71e5 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_answer_aaaa.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include <skalibs/stralloc.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_parse_answer_aaaa (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *stuff) +{ + if ((section == 2) && (rr->rtype == S6DNS_T_AAAA) && (rr->rdlength == 16)) + { + stralloc *data = stuff ; + if (!stralloc_catb(data, packet + pos, 16)) return -1 ; + } + (void)packetlen ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_parse_answer_domain.c b/src/libs6dns/s6dns_message_parse_answer_domain.c new file mode 100644 index 0000000..d09abc9 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_answer_domain.c @@ -0,0 +1,21 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genalloc.h> +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_parse_answer_domain (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *stuff) +{ + s6dns_dpag_t *data = stuff ; + if ((section == 2) && (rr->rtype == data->rtype)) + { + s6dns_domain_t d ; + register unsigned int start = pos ; + if (!s6dns_message_get_domain(&d, packet, packetlen, &pos)) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + if (!genalloc_append(s6dns_domain_t, &data->ds, &d)) return -1 ; + } + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_parse_answer_hinfo.c b/src/libs6dns/s6dns_message_parse_answer_hinfo.c new file mode 100644 index 0000000..aa53601 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_answer_hinfo.c @@ -0,0 +1,21 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genalloc.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_parse_answer_hinfo (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *stuff) +{ + if ((section == 2) && (rr->rtype == S6DNS_T_HINFO)) + { + genalloc *data = stuff ; + s6dns_message_rr_hinfo_t hinfo ; + register unsigned int start = pos ; + if (!s6dns_message_get_hinfo(&hinfo, packet, packetlen, &pos)) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + if (!genalloc_append(s6dns_message_rr_hinfo_t, data, &hinfo)) return -1 ; + } + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_parse_answer_mx.c b/src/libs6dns/s6dns_message_parse_answer_mx.c new file mode 100644 index 0000000..32f43c9 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_answer_mx.c @@ -0,0 +1,21 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genalloc.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_parse_answer_mx (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *stuff) +{ + if ((section == 2) && (rr->rtype == S6DNS_T_MX)) + { + genalloc *data = stuff ; + s6dns_message_rr_mx_t mx ; + register unsigned int start = pos ; + if (!s6dns_message_get_mx(&mx, packet, packetlen, &pos)) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + if (!genalloc_append(s6dns_message_rr_mx_t, data, &mx)) return -1 ; + } + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_parse_answer_soa.c b/src/libs6dns/s6dns_message_parse_answer_soa.c new file mode 100644 index 0000000..6c7b668 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_answer_soa.c @@ -0,0 +1,21 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genalloc.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_parse_answer_soa (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *stuff) +{ + if ((section == 2) && (rr->rtype == S6DNS_T_SOA)) + { + genalloc *data = stuff ; + s6dns_message_rr_soa_t soa ; + register unsigned int start = pos ; + if (!s6dns_message_get_soa(&soa, packet, packetlen, &pos)) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + if (!genalloc_append(s6dns_message_rr_soa_t, data, &soa)) return -1 ; + } + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_parse_answer_srv.c b/src/libs6dns/s6dns_message_parse_answer_srv.c new file mode 100644 index 0000000..31be348 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_answer_srv.c @@ -0,0 +1,21 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/genalloc.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_parse_answer_srv (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *stuff) +{ + if ((section == 2) && (rr->rtype == S6DNS_T_SRV)) + { + genalloc *data = stuff ; + s6dns_message_rr_srv_t srv ; + register unsigned int start = pos ; + if (!s6dns_message_get_srv(&srv, packet, packetlen, &pos)) return 0 ; + if (rr->rdlength != pos - start) return (errno = EPROTO, 0) ; + if (!genalloc_append(s6dns_message_rr_srv_t, data, &srv)) return -1 ; + } + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_parse_answer_strings.c b/src/libs6dns/s6dns_message_parse_answer_strings.c new file mode 100644 index 0000000..09470c7 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_answer_strings.c @@ -0,0 +1,36 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_parse_answer_strings (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *stuff) +{ + s6dns_mpag_t_ref data = stuff ; + if ((section == 2) && (rr->rtype == data->rtype)) + { + unsigned int base = data->sa.len ; + int wasnull = !data->sa.s ; + unsigned int start = pos ; + register int r ; + if (!stralloc_readyplus(&data->sa, rr->rdlength + 1)) return -1 ; + errno = EPROTO ; + r = s6dns_message_get_strings(data->sa.s + data->sa.len, rr->rdlength, packet, packetlen, &pos) ; + if ((r < 0) || (rr->rdlength != pos - start)) + { + if (wasnull) stralloc_free(&data->sa) ; else data->sa.len = base ; + return 0 ; + } + if (!genalloc_append(unsigned int, &data->offsets, &data->sa.len)) + { + if (wasnull) stralloc_free(&data->sa) ; else data->sa.len = base ; + return -1 ; + } + errno = 0 ; + data->sa.len += r ; + stralloc_0(&data->sa) ; + } + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_parse_getrr.c b/src/libs6dns/s6dns_message_parse_getrr.c new file mode 100644 index 0000000..8db0c5d --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_getrr.c @@ -0,0 +1,19 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_parse_getrr (s6dns_message_rr_t_ref rr, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + if (!s6dns_message_get_domain(&rr->name, packet, packetlen, pos)) return 0 ; + if (*pos + 10 > packetlen) return (errno = EPROTO, 0) ; + uint16_unpack_big(packet + *pos, &rr->rtype) ; *pos += 2 ; + uint16_unpack_big(packet + *pos, &rr->rclass) ; *pos += 2 ; + uint32_unpack_big(packet + *pos, &rr->ttl) ; *pos += 4 ; + uint16_unpack_big(packet + *pos, &rr->rdlength) ; *pos += 2 ; + if (*pos + rr->rdlength > packetlen) return (errno = EPROTO, 0) ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_parse_init.c b/src/libs6dns/s6dns_message_parse_init.c new file mode 100644 index 0000000..3b4efc5 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_init.c @@ -0,0 +1,13 @@ +/* ISC license. */ + +#include <errno.h> +#include <s6-dns/s6dns-message.h> + +int s6dns_message_parse_init (s6dns_message_header_t *h, s6dns_message_counts_t *counts, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + if (packetlen < 12) return (errno = EPROTO, 0) ; + s6dns_message_header_unpack(packet, h) ; + *counts = h->counts ; + *pos = 12 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_message_parse_next.c b/src/libs6dns/s6dns_message_parse_next.c new file mode 100644 index 0000000..a7bbce6 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_next.c @@ -0,0 +1,11 @@ +/* ISC license. */ + +#include <errno.h> +#include <s6-dns/s6dns-message.h> + +unsigned int s6dns_message_parse_next (s6dns_message_counts_t *counts, s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + *pos += rr->rdlength ; + (void)packet ; (void)packetlen ; + return s6dns_message_counts_next(counts) ; +} diff --git a/src/libs6dns/s6dns_message_parse_skipqd.c b/src/libs6dns/s6dns_message_parse_skipqd.c new file mode 100644 index 0000000..9b8c222 --- /dev/null +++ b/src/libs6dns/s6dns_message_parse_skipqd.c @@ -0,0 +1,15 @@ +/* ISC license. */ + +#include <s6-dns/s6dns-message.h> +#include "s6dns-message-internal.h" + +unsigned int s6dns_message_parse_skipqd (s6dns_message_counts_t *counts, char const *packet, unsigned int packetlen, unsigned int *pos) +{ + for (;;) + { + register unsigned int r = s6dns_message_counts_next(counts) ; + if (r != 1) return r ; + if (!s6dns_message_get_domain_internal(0, 255, packet, packetlen, pos)) return 0 ; + *pos += 4 ; + } +} diff --git a/src/libs6dns/s6dns_rci_free.c b/src/libs6dns/s6dns_rci_free.c new file mode 100644 index 0000000..d742ffe --- /dev/null +++ b/src/libs6dns/s6dns_rci_free.c @@ -0,0 +1,10 @@ +/* ISC license. */ + +#include <skalibs/stralloc.h> +#include <s6-dns/s6dns-rci.h> + +void s6dns_rci_free (s6dns_rci_t *rci) +{ + stralloc_free(&rci->rules) ; + *rci = s6dns_rci_zero ; +} diff --git a/src/libs6dns/s6dns_rci_here.c b/src/libs6dns/s6dns_rci_here.c new file mode 100644 index 0000000..2f08513 --- /dev/null +++ b/src/libs6dns/s6dns_rci_here.c @@ -0,0 +1,7 @@ +/* ISC license. */ + +/* MT-unsafe */ + +#include <s6-dns/s6dns-rci.h> + +s6dns_rci_t s6dns_rci_here = S6DNS_RCI_ZERO ; diff --git a/src/libs6dns/s6dns_rci_init.c b/src/libs6dns/s6dns_rci_init.c new file mode 100644 index 0000000..a4f3fcf --- /dev/null +++ b/src/libs6dns/s6dns_rci_init.c @@ -0,0 +1,173 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/bytestr.h> +#include <skalibs/bitarray.h> +#include <skalibs/fmtscan.h> +#include <skalibs/tai.h> +#include <skalibs/djbunix.h> +#include <skalibs/stralloc.h> +#include <skalibs/ip46.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-rci.h> + +static unsigned int readit (char const *file, char *buf, unsigned int max) +{ + register int r = openreadnclose(file, buf, max - 1) ; + if (r < 0) + { + if (errno != ENOENT) return 0 ; + else r = 0 ; + } + buf[r++] = '\n' ; + return (unsigned int)r ; +} + +static inline int s6dns_rci_init_servers (s6dns_rci_t *rci, char const *file, char *tmp, unsigned int max, unsigned int *size) +{ + ip46_t tmplist[S6DNS_MAX_SERVERS] ; + unsigned int num = 0 ; + char const *x = env_get("DNSCACHEIP") ; + if (x) ip46_scanlist(tmplist, S6DNS_MAX_SERVERS, x, &num) ; + if (!num) + { + unsigned int i = 0 ; + *size = readit(file, tmp, max) ; + if (!*size) return 0 ; + while ((i < *size) && (num < S6DNS_MAX_SERVERS)) + { + register unsigned int j = byte_chr(tmp + i, *size - i, '\n') ; + if ((i + j < *size) && (j > 13U) && !byte_diff("nameserver", 10, tmp + i)) + { + register unsigned int k = 0 ; + while ((tmp[i+10+k] == ' ') || (tmp[i+10+k] == '\t')) k++ ; + if (k && ip46_scan(tmp+i+10+k, tmplist + num)) num++ ; + } + i += j + 1 ; + } + } + if (!num) + { + num = 1 ; + byte_copy(tmplist[0].ip, SKALIBS_IP_SIZE, S6DNS_LOCALHOST_IP) ; +#ifdef SKALIBS_IPV6_ENABLED + tmplist[0].is6 = 1 ; +#endif + } + + { + register unsigned int i = 0 ; + byte_zero(&rci->servers, sizeof(s6dns_ip46list_t)) ; + for (; i < num ; i++) + { + byte_copy(rci->servers.ip + SKALIBS_IP_SIZE * i, SKALIBS_IP_SIZE, tmplist[i].ip) ; +#ifdef SKALIBS_IPV6_ENABLED + if (ip46_is6(tmplist+i)) bitarray_set(rci->servers.is6, i) ; +#endif + } + } + return 1 ; +} + +static inline int stringrules (stralloc *rules, char const *s, unsigned int *num) +{ + unsigned int n = 0 ; + int crunching = 1 ; + int wasnull = !rules->s ; + unsigned int base = rules->len ; + char c = ' ' ; + while (c) + { + c = *s++ ; + if (byte_chr(" \t\n\r", 5, c) < 5) + { + if (!crunching) + { + if ((rules->s[rules->len - 1] != '.') && !stralloc_catb(rules, ".", 1)) goto err ; + if (!stralloc_0(rules)) goto err ; + n++ ; + crunching = 1 ; + } + } + else + { + if (crunching) crunching = 0 ; + if (!stralloc_catb(rules, &c, 1)) goto err ; + } + } + *num += n ; + return 1 ; + + err: + if (wasnull) stralloc_free(rules) ; + else rules->len = base ; + return 0 ; +} + +static inline int s6dns_rci_init_rules (s6dns_rci_t_ref rci, char const *file, char *tmp, unsigned int max, unsigned int *size) +{ + unsigned int num = 0 ; + char const *x = env_get("DNSQUALIFY") ; + if (x) + { + if (!stringrules(&rci->rules, x, &num)) return 0 ; + } + else + { + unsigned int i = 0 ; + if (!*size) + { + *size = readit(file, tmp, max) ; + if (!*size) return 0 ; + } + while (i < *size) + { + register unsigned int j = byte_chr(tmp + i, *size - i, '\n') ; + if ((i + j < *size) && (j > 8U) + && (!byte_diff("domain", 6, tmp + i) || !byte_diff("search", 6, tmp + i)) + && ((tmp[i+6] == ' ') || (tmp[i+6] == '\t') || (tmp[i+6] == '\r'))) + { + unsigned int k = 0 ; + int copying = 0 ; + register int notsearching = (tmp[i] != 's') ; + if (!stralloc_readyplus(&rci->rules, j)) return 0 ; + for (; 6 + k < j ; k++) + { + char c = tmp[i+7+k] ; + if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n')) + { + if (copying) + { + copying = 0 ; + if ((tmp[i+6+k] != '.') && !stralloc_catb(&rci->rules, ".", 1)) return 0 ; + if (!stralloc_0(&rci->rules)) return 0 ; + num++ ; + if (notsearching) break ; + } + } + else + { + copying = 1 ; + if (!stralloc_catb(&rci->rules, &c, 1)) return 0 ; + } + } + } + i += j + 1 ; + } + } + if (!stralloc_0(&rci->rules)) return 0 ; /* empty rule to finish */ + num++ ; + rci->rulesnum = num ; + stralloc_shrink(&rci->rules) ; + return 1 ; +} + +int s6dns_rci_init (s6dns_rci_t *rci, char const *file) +{ + char tmp[4096] ; + unsigned int size = 0 ; + if (!s6dns_rci_init_servers(rci, file, tmp, 4096, &size)) return 0 ; + if (!s6dns_rci_init_rules(rci, file, tmp, 4096, &size)) return 0 ; + return 1 ; +} diff --git a/src/libs6dns/s6dns_rci_zero.c b/src/libs6dns/s6dns_rci_zero.c new file mode 100644 index 0000000..384b42a --- /dev/null +++ b/src/libs6dns/s6dns_rci_zero.c @@ -0,0 +1,7 @@ +/* ISC license. */ + +/* MT-unsafe */ + +#include <s6-dns/s6dns-rci.h> + +s6dns_rci_t const s6dns_rci_zero = S6DNS_RCI_ZERO ; diff --git a/src/libs6dns/s6dns_resolve_core.c b/src/libs6dns/s6dns_resolve_core.c new file mode 100644 index 0000000..0b75f07 --- /dev/null +++ b/src/libs6dns/s6dns_resolve_core.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/tai.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-ip46.h> +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/s6dns-engine.h> +#include <s6-dns/s6dns-resolve.h> + +int s6dns_resolve_core_r (s6dns_domain_t const *d, uint16 qtype, s6dns_engine_t *dt, s6dns_ip46list_t const *servers, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) +{ + return s6dns_engine_init_r(dt, servers, S6DNS_O_RECURSIVE, d->s, d->len, qtype, dbh, deadline, stamp) + && s6dns_resolve_loop_r(dt, deadline, stamp) ; +} diff --git a/src/libs6dns/s6dns_resolve_dpag.c b/src/libs6dns/s6dns_resolve_dpag.c new file mode 100644 index 0000000..7c735b8 --- /dev/null +++ b/src/libs6dns/s6dns_resolve_dpag.c @@ -0,0 +1,20 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <skalibs/tai.h> +#include <skalibs/genalloc.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> + +int s6dns_resolve_dpag_r (genalloc *ds, char const *name, unsigned int len, uint16 qtype, int qualif, s6dns_engine_t *dt, s6dns_rci_t const *rci, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) +{ + s6dns_dpag_t data ; + register int r ; + data.ds = *ds ; + data.rtype = qtype ; + r = s6dns_resolve_r(name, len, qtype, &s6dns_message_parse_answer_domain, &data, qualif, dt, rci, dbh, deadline, stamp) ; + *ds = data.ds ; + return r ; +} diff --git a/src/libs6dns/s6dns_resolve_mpag.c b/src/libs6dns/s6dns_resolve_mpag.c new file mode 100644 index 0000000..a6e04cb --- /dev/null +++ b/src/libs6dns/s6dns_resolve_mpag.c @@ -0,0 +1,23 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <skalibs/tai.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.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> + +int s6dns_resolve_mpag_r (stralloc *sa, genalloc *offsets, char const *name, unsigned int len, uint16 qtype, s6dns_message_rr_func_t_ref parsefunc, int qualif, s6dns_engine_t *dt, s6dns_rci_t const *rci, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) +{ + s6dns_mpag_t data ; + register int r ; + data.sa = *sa ; + data.offsets = *offsets ; + data.rtype = qtype ; + r = s6dns_resolve_r(name, len, qtype, parsefunc, &data, qualif, dt, rci, dbh, deadline, stamp) ; + *sa = data.sa ; + *offsets = data.offsets ; + return r ; +} diff --git a/src/libs6dns/s6dns_resolve_name4.c b/src/libs6dns/s6dns_resolve_name4.c new file mode 100644 index 0000000..7bb504a --- /dev/null +++ b/src/libs6dns/s6dns_resolve_name4.c @@ -0,0 +1,23 @@ +/* ISC license. */ + +#include <skalibs/tai.h> +#include <skalibs/genalloc.h> +#include <s6-dns/s6dns-constants.h> +#include <s6-dns/s6dns-ip46.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-engine.h> +#include <s6-dns/s6dns-resolve.h> + +int s6dns_resolve_name4_r (genalloc *list, char const *ip, s6dns_engine_t *dt, s6dns_ip46list_t const *servers, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) +{ + s6dns_dpag_t data ; + s6dns_domain_t d ; + register int r ; + s6dns_domain_arpafromip4(&d, ip) ; + s6dns_domain_encode(&d) ; + data.ds = *list ; + data.rtype = S6DNS_T_PTR ; + r = s6dns_resolve_parse_r(&d, data.rtype, &s6dns_message_parse_answer_domain, &data, dt, servers, dbh, deadline, stamp) ; + *list = data.ds ; + return r ; +} diff --git a/src/libs6dns/s6dns_resolve_name6.c b/src/libs6dns/s6dns_resolve_name6.c new file mode 100644 index 0000000..1af3945 --- /dev/null +++ b/src/libs6dns/s6dns_resolve_name6.c @@ -0,0 +1,24 @@ +/* ISC license. */ + +#include <skalibs/tai.h> +#include <skalibs/genalloc.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-resolve.h> + +int s6dns_resolve_name6_r (genalloc *list, char const *ip, s6dns_engine_t *dt, s6dns_ip46list_t const *servers, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) +{ + s6dns_dpag_t data ; + s6dns_domain_t d ; + register int r ; + s6dns_domain_arpafromip6(&d, ip, 128) ; + s6dns_domain_encode(&d) ; + data.ds = *list ; + data.rtype = S6DNS_T_PTR ; + r = s6dns_resolve_parse_r(&d, data.rtype, &s6dns_message_parse_answer_domain, &data, dt, servers, dbh, deadline, stamp) ; + *list = data.ds ; + return r ; +} diff --git a/src/libs6dns/s6dns_resolve_parse.c b/src/libs6dns/s6dns_resolve_parse.c new file mode 100644 index 0000000..b00804f --- /dev/null +++ b/src/libs6dns/s6dns_resolve_parse.c @@ -0,0 +1,21 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <skalibs/tai.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-resolve.h> + +int s6dns_resolve_parse_r (s6dns_domain_t const *d, uint16 qtype, s6dns_message_rr_func_t_ref parsefunc, void *data, s6dns_engine_t *dt, s6dns_ip46list_t const *servers, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) +{ + register int r ; + if (!s6dns_resolve_core_r(d, qtype, dt, servers, dbh, deadline, stamp)) return -1 ; + { + s6dns_message_header_t h ; + r = s6dns_message_parse(&h, s6dns_engine_packet(dt), s6dns_engine_packetlen(dt), parsefunc, data) ; + } + s6dns_engine_recycle(dt) ; + return r ; +} diff --git a/src/libs6dns/s6dns_resolven_loop.c b/src/libs6dns/s6dns_resolven_loop.c new file mode 100644 index 0000000..6e0c3b4 --- /dev/null +++ b/src/libs6dns/s6dns_resolven_loop.c @@ -0,0 +1,54 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/tai.h> +#include <skalibs/iopause.h> +#include <s6-dns/s6dns-engine.h> +#include <s6-dns/s6dns-resolve.h> + + /* + This is basically a synchronous interface to s6dns_engine. + It resolves n dts at the same time. + */ + +int s6dns_resolven_loop (s6dns_engine_t *dt, unsigned int n, unsigned int or, tain_t const *deadline, tain_t *stamp) +{ + iopause_fd x[n] ; + unsigned int count = 0 ; + for (;;) + { + tain_t localdeadline = *deadline ; + register int r ; + register unsigned int i = 0 ; + register unsigned int j = 0 ; + for (; i < n ; i++) if (dt[i].status == EAGAIN) + { + s6dns_engine_nextdeadline(dt + i, &localdeadline) ; + x[j].fd = dt[i].fd ; + x[j].events = (s6dns_engine_isreadable(dt + i) ? IOPAUSE_READ : 0) | (s6dns_engine_iswritable(dt + i) ? IOPAUSE_WRITE : 0) ; + j++ ; + } + if (!j) break ; + r = iopause_stamp(x, j, &localdeadline, stamp) ; + if (r < 0) return -1 ; + else if (!r) + { + if (tain_less(deadline, stamp)) return (errno = ETIMEDOUT, -1) ; + for (i = 0 ; i < n ; i++) if (dt[i].status == EAGAIN) + if (s6dns_engine_timeout(dt + i, stamp) && (or >= 2)) return i ; + } + else + { + for (i = 0 ; i < n ; i++) if (dt[i].status == EAGAIN) + { + r = s6dns_engine_event(dt + i, stamp) ; + if (or) + { + if (r && ((r > 0) || (or >= 2))) return i ; + } + else if (r > 0) count++ ; + } + } + } + return or ? (errno = ENOENT, -1) : (int)count ; +} diff --git a/src/libs6dns/s6dns_resolven_parse.c b/src/libs6dns/s6dns_resolven_parse.c new file mode 100644 index 0000000..78289bc --- /dev/null +++ b/src/libs6dns/s6dns_resolven_parse.c @@ -0,0 +1,47 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/tai.h> +#include <skalibs/iopause.h> +#include <s6-dns/s6dns-ip46.h> +#include <s6-dns/s6dns-message.h> +#include <s6-dns/s6dns-engine.h> +#include <s6-dns/s6dns-resolve.h> + +int s6dns_resolven_parse_r (s6dns_resolve_t *list, unsigned int n, s6dns_ip46list_t const *servers, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) +{ + s6dns_engine_t dtl[n] ; + register unsigned int i = 0 ; + for (; i < n ; i++) list[i].status = ECONNABORTED ; + for (i = 0 ; i < n ; i++) + { + dtl[i] = s6dns_engine_zero ; + if (!s6dns_engine_init_r(dtl + i, servers, list[i].options, list[i].q.s, list[i].q.len, list[i].qtype, dbh, &list[i].deadline, stamp)) + { + list[i].status = errno ; + s6dns_engine_freen(dtl, i) ; + return 0 ; + } + list[i].status = EAGAIN ; + } + + if (s6dns_resolven_loop(dtl, n, 0, deadline, stamp) < 0) goto err ; + + for (i = 0 ; i < n ; i++) + { + if (dtl[i].status) list[i].status = dtl[i].status ; + else + { + s6dns_message_header_t h ; + register int r = s6dns_message_parse(&h, s6dns_engine_packet(dtl + i), s6dns_engine_packetlen(dtl + i), list[i].parsefunc, list[i].data) ; + if (r < 0) goto err ; + list[i].status = r ? 0 : errno ; + } + } + s6dns_engine_freen(dtl, n) ; + return 1 ; + + err: + s6dns_engine_freen(dtl, n) ; + return 0 ; +} diff --git a/src/libs6dns/s6dns_resolvenoq.c b/src/libs6dns/s6dns_resolvenoq.c new file mode 100644 index 0000000..3462076 --- /dev/null +++ b/src/libs6dns/s6dns_resolvenoq.c @@ -0,0 +1,16 @@ + /* ISC license. */ + +#include <skalibs/uint16.h> +#include <skalibs/tai.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-resolve.h> + +int s6dns_resolvenoq_r (char const *name, unsigned int len, uint16 qtype, s6dns_message_rr_func_t_ref parsefunc, void *data, s6dns_engine_t *dt, s6dns_ip46list_t const *servers, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) +{ + s6dns_domain_t d ; + if (!s6dns_domain_fromstring_noqualify_encode(&d, name, len)) return -1 ; + return s6dns_resolve_parse_r(&d, qtype, parsefunc, data, dt, servers, dbh, deadline, stamp) ; +} diff --git a/src/libs6dns/s6dns_resolvenoq_aaaaa.c b/src/libs6dns/s6dns_resolvenoq_aaaaa.c new file mode 100644 index 0000000..b280fe0 --- /dev/null +++ b/src/libs6dns/s6dns_resolvenoq_aaaaa.c @@ -0,0 +1,50 @@ +/* ISC license. */ + +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/tai.h> +#include <skalibs/ip46.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-resolve.h> + +int s6dns_resolvenoq_aaaaa_r (genalloc *ips, char const *name, unsigned int len, s6dns_ip46list_t const *servers, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) +{ + stralloc sa[2] = { STRALLOC_ZERO, STRALLOC_ZERO } ; + s6dns_resolve_t blob[2] ; + if (!s6dns_domain_fromstring_noqualify_encode(&blob[0].q, name, len)) return -1 ; + blob[0].qtype = S6DNS_T_AAAA ; + blob[0].options = S6DNS_O_RECURSIVE ; + blob[0].deadline = *deadline ; + blob[0].parsefunc = &s6dns_message_parse_answer_aaaa ; + blob[0].data = &sa[0] ; + blob[1].q = blob[0].q ; + blob[1].qtype = S6DNS_T_A ; + blob[1].options = S6DNS_O_RECURSIVE ; + blob[1].deadline = *deadline ; + blob[1].parsefunc = &s6dns_message_parse_answer_a ; + blob[1].data = &sa[1] ; + if (!s6dns_resolven_parse_r(blob, 2, servers, dbh, deadline, stamp)) return -1 ; + if (blob[0].status && blob[1].status) return (errno = blob[1].status, 0) ; + if (!genalloc_readyplus(ip46_t, ips, (sa[0].len >> 4) + (sa[1].len >> 2))) + { + stralloc_free(&sa[0]) ; + stralloc_free(&sa[1]) ; + return -1 ; + } + { + unsigned int n = genalloc_len(ip46_t, ips) ; + int e = (!!sa[0].len << 1) | !!sa[1].len ; + register unsigned int i = 0 ; + for (; i < (sa[0].len >> 4) ; i++) + ip46_from_ip6(genalloc_s(ip46_t, ips) + n++, sa[0].s + (i << 4)) ; + for (i = 0 ; i < (sa[1].len >> 2) ; i++) + ip46_from_ip4(genalloc_s(ip46_t, ips) + n++, sa[1].s + (i << 2)) ; + genalloc_setlen(ip46_t, ips, n) ; + stralloc_free(&sa[0]) ; + stralloc_free(&sa[1]) ; + return e ; + } +} diff --git a/src/libs6dns/s6dns_resolveq.c b/src/libs6dns/s6dns_resolveq.c new file mode 100644 index 0000000..c43db1f --- /dev/null +++ b/src/libs6dns/s6dns_resolveq.c @@ -0,0 +1,89 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/error.h> +#include <skalibs/tai.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> + +int s6dns_resolveq_r (char const *name, unsigned int len, uint16 qtype, s6dns_message_rr_func_t_ref parsefunc, void *data, s6dns_rci_t const *rci, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) +{ + s6dns_engine_t dtl[rci->rulesnum] ; + unsigned int best = 0 ; + unsigned int n ; + int e = 0 ; + register unsigned int i = 0 ; + { + s6dns_domain_t domains[rci->rulesnum] ; + n = s6dns_domain_fromstring_qualify_encode(domains, name, len, rci->rules.s, rci->rulesnum) ; + if (!n) return -1 ; + for (; i < n ; i++) + { + dtl[i] = s6dns_engine_zero ; + if (!s6dns_engine_init_r(dtl + i, &rci->servers, S6DNS_O_RECURSIVE, domains[i].s, domains[i].len, qtype, dbh, deadline, stamp)) + { + s6dns_engine_freen(dtl, i) ; + return -1 ; + } + } + } + + /* + Wait until the "best" answer arrives, then scan until a positive answer + is found. + + dtl[i].status == EAGAIN : query still pending + other nonzero dtl[i].status : error, give up + dtl[i].status == 0 : answer #i has arrived, in which case parse it; + r < 0 : error, give up + r > 0 : positive answer, return it + r == 0 : negative answer. If it's non-fatal (i.e. NXDOMAIN), + then move on to the next best FQDN. + */ + + for (;;) + { + register int k = s6dns_resolven_loop(dtl, n, 1, deadline, stamp) ; + if (k < 0) goto err ; + if ((unsigned int)k == best) + { + for (;; best++) + { + s6dns_message_header_t h ; + register int r ; + if (best >= n) goto notfound ; + if (error_isagain(dtl[best].status)) break ; + if (dtl[best].status) { errno = dtl[best].status ; goto err ; } + r = s6dns_message_parse(&h, s6dns_engine_packet(dtl + best), s6dns_engine_packetlen(dtl + best), parsefunc, data) ; + if (r < 0) goto err ; + else if (r) goto found ; + else switch (errno) + { + case EBUSY : + case ENOENT : + case ECONNREFUSED : + case EIO : + break ; + default : goto err ; + } + if (!best) e = errno ; + } + } + } + + found: + s6dns_engine_freen(dtl, n) ; + return 1 ; + + notfound: + s6dns_engine_freen(dtl, n) ; + return (errno = e, 0) ; + + err: + s6dns_engine_freen(dtl, n) ; + return -1 ; +} diff --git a/src/libs6dns/s6dns_resolveq_aaaaa.c b/src/libs6dns/s6dns_resolveq_aaaaa.c new file mode 100644 index 0000000..825e68e --- /dev/null +++ b/src/libs6dns/s6dns_resolveq_aaaaa.c @@ -0,0 +1,96 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/error.h> +#include <skalibs/stralloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/tai.h> +#include <skalibs/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> + +int s6dns_resolveq_aaaaa_r (genalloc *ips, char const *name, unsigned int len, s6dns_rci_t const *rci, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) +{ + s6dns_engine_t dtl[rci->rulesnum << 1] ; + stralloc data = STRALLOC_ZERO ; + unsigned int best = 0 ; + unsigned int n ; + int e = 0 ; + register unsigned int i = 0 ; + { + s6dns_domain_t domains[rci->rulesnum] ; + n = s6dns_domain_fromstring_qualify_encode(domains, name, len, rci->rules.s, rci->rulesnum) ; + if (!n) return -1 ; + for (; i < n ; i++) + { + dtl[i<<1] = s6dns_engine_zero ; + if (!s6dns_engine_init_r(dtl + (i<<1), &rci->servers, S6DNS_O_RECURSIVE, domains[i].s, domains[i].len, S6DNS_T_AAAA, dbh, deadline, stamp)) + { + s6dns_engine_freen(dtl, i<<1) ; + return -1 ; + } + dtl[(i<<1)+1] = s6dns_engine_zero ; + if (!s6dns_engine_init_r(dtl + (i<<1) + 1, &rci->servers, S6DNS_O_RECURSIVE, domains[i].s, domains[i].len, S6DNS_T_A, dbh, deadline, stamp)) + { + s6dns_engine_freen(dtl, (i<<1)+1) ; + return -1 ; + } + } + } + + for (;;) + { + register int k = s6dns_resolven_loop(dtl, n << 1, 1, deadline, stamp) ; + if (k < 0) goto err ; + if ((unsigned int)k == best) + { + for (;; best++) + { + s6dns_message_header_t h ; + register int r ; + if (best >= n << 1) goto notfound ; + if (error_isagain(dtl[best].status)) break ; + if (dtl[best].status) { errno = dtl[best].status ; goto err ; } + r = s6dns_message_parse(&h, s6dns_engine_packet(dtl + best), s6dns_engine_packetlen(dtl + best), (best & 1) ? &s6dns_message_parse_answer_a : s6dns_message_parse_answer_aaaa, &data) ; + if (r < 0) goto err ; + else if (r) goto found ; + else switch (errno) + { + case EBUSY : + case ENOENT : + case ECONNREFUSED : + case EIO : + break ; + default : goto err ; + } + if (!best) e = errno ; + } + } + } + + found: + s6dns_engine_freen(dtl, n<<1) ; + { + register unsigned int len = data.len >> ((best & 1) ? 2 : 4) ; + register unsigned int i = 0 ; + register unsigned int base = genalloc_len(ip46_t, ips) ; + if (!genalloc_readyplus(ip46_t, ips, len)) return -1 ; + for (; i < len ; i++) + ip46_from_ip(genalloc_s(ip46_t, ips) + base + i, data.s + (i << ((best & 1) ? 2 : 4)), !(best & 1)) ; + genalloc_setlen(ip46_t, ips, base + len) ; + } + stralloc_free(&data) ; + return 1 ; + + notfound: + s6dns_engine_freen(dtl, n<<1) ; + return (errno = e, 0) ; + + err: + s6dns_engine_freen(dtl, n<<1) ; + return -1 ; +} diff --git a/src/skadns/deps-exe/skadnsd b/src/skadns/deps-exe/skadnsd new file mode 100755 index 0000000..4181fd6 --- /dev/null +++ b/src/skadns/deps-exe/skadnsd @@ -0,0 +1,4 @@ +-ls6dns +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/skadns/deps-lib/skadns b/src/skadns/deps-lib/skadns new file mode 100644 index 0000000..570a6f5 --- /dev/null +++ b/src/skadns/deps-lib/skadns @@ -0,0 +1,10 @@ +skadns_cancel.o +skadns_end.o +skadns_packet.o +skadns_packetlen.o +skadns_release.o +skadns_send.o +skadns_start.o +skadns_startf.o +skadns_update.o +skadns_zero.o diff --git a/src/skadns/skadns_cancel.c b/src/skadns/skadns_cancel.c new file mode 100644 index 0000000..13db918 --- /dev/null +++ b/src/skadns/skadns_cancel.c @@ -0,0 +1,23 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/error.h> +#include <skalibs/tai.h> +#include <skalibs/gensetdyn.h> +#include <skalibs/skaclient.h> +#include <s6-dns/skadns.h> + +int skadns_cancel (skadns_t *a, uint16 id, tain_t const *deadline, tain_t *stamp) +{ + char pack[3] = "--q" ; + char err ; + register skadnsanswer_t *p = GENSETDYN_P(skadnsanswer_t, &a->q, id) ; + if (!error_isagain(p->status)) return skadns_release(a, id) ; + uint16_pack_big(pack, id) ; + if (!skaclient_send(&a->connection, pack, 3, &skaclient_default_cb, &err, deadline, stamp)) return 0 ; + if (!err) return gensetdyn_delete(&a->q, id) ; + if (err != ENOENT) return (errno = err, 0) ; + p->status = ECANCELED ; + return 1 ; +} diff --git a/src/skadns/skadns_end.c b/src/skadns/skadns_end.c new file mode 100644 index 0000000..6f5f01b --- /dev/null +++ b/src/skadns/skadns_end.c @@ -0,0 +1,24 @@ +/* ISC license. */ + +#include <skalibs/alloc.h> +#include <skalibs/genalloc.h> +#include <skalibs/gensetdyn.h> +#include <skalibs/skaclient.h> +#include <s6-dns/skadns.h> + +static int skadnsanswer_free (char *p, void *stuff) +{ + register skadnsanswer_t *q = (skadnsanswer_t_ref)p ; + alloc_free(&q->data) ; + (void)stuff ; + return 1 ; +} + +void skadns_end (skadns_t *a) +{ + skaclient_end(&a->connection) ; + genalloc_free(uint16, &a->list) ; + gensetdyn_iter(&a->q, &skadnsanswer_free, 0) ; + gensetdyn_free(&a->q) ; + *a = skadns_zero ; +} diff --git a/src/skadns/skadns_packet.c b/src/skadns/skadns_packet.c new file mode 100644 index 0000000..c34b3a1 --- /dev/null +++ b/src/skadns/skadns_packet.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/gensetdyn.h> +#include <s6-dns/skadns.h> + +char const *skadns_packet (skadns_t const *a, uint16 id) +{ + register skadnsanswer_t *p = GENSETDYN_P(skadnsanswer_t, &a->q, id) ; + switch (p->status) + { + case 0 : return (char const *)p->data ; + default : return (errno = p->status, (char const *)0) ; + } +} diff --git a/src/skadns/skadns_packetlen.c b/src/skadns/skadns_packetlen.c new file mode 100644 index 0000000..34cbb28 --- /dev/null +++ b/src/skadns/skadns_packetlen.c @@ -0,0 +1,16 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/gensetdyn.h> +#include <s6-dns/skadns.h> + +int skadns_packetlen (skadns_t const *a, uint16 id) +{ + register skadnsanswer_t *p = GENSETDYN_P(skadnsanswer_t, &a->q, id) ; + switch (p->status) + { + case 0 : return p->len ; + default : return (errno = p->status, -1) ; + } +} diff --git a/src/skadns/skadns_release.c b/src/skadns/skadns_release.c new file mode 100644 index 0000000..9fba737 --- /dev/null +++ b/src/skadns/skadns_release.c @@ -0,0 +1,26 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/alloc.h> +#include <skalibs/gensetdyn.h> +#include <s6-dns/skadns.h> + +int skadns_release (skadns_t *a, uint16 id) +{ + register skadnsanswer_t *p = GENSETDYN_P(skadnsanswer_t, &a->q, id) ; + switch (p->status) + { + case 0 : + alloc_free(p->data) ; p->data = 0 ; p->len = 0 ; + break ; + case EAGAIN : + case ECANCELED : + return (errno = EBUSY, 0) ; + case EINVAL : + return (errno = EINVAL, 0) ; + default : break ; + } + p->status = EINVAL ; + return gensetdyn_delete(&a->q, id) ; +} diff --git a/src/skadns/skadns_send.c b/src/skadns/skadns_send.c new file mode 100644 index 0000000..7ee04c7 --- /dev/null +++ b/src/skadns/skadns_send.c @@ -0,0 +1,41 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/bytestr.h> +#include <skalibs/siovec.h> +#include <skalibs/tai.h> +#include <skalibs/stralloc.h> +#include <skalibs/gensetdyn.h> +#include <skalibs/skaclient.h> +#include <s6-dns/s6dns-domain.h> +#include <s6-dns/skadns.h> + +static skadnsanswer_t const skadnsanswer_initial = { .status = EAGAIN, .data = 0, .len = 0 } ; + +int skadns_send (skadns_t *a, uint16 *u, s6dns_domain_t const *d, uint16 qtype, tain_t const *limit, tain_t const *deadline, tain_t *stamp) +{ + unsigned int i ; + char tmp[17] = "--Q" ; + char err ; + siovec_t v[2] = { { .s = tmp, .len = 17 }, { .s = d->s, .len = d->len } } ; + if (!gensetdyn_new(&a->q, &i)) return 0 ; + uint16_pack_big(tmp, (uint16)i) ; + uint16_pack_big(tmp + 3, qtype) ; + if (limit) tain_pack(tmp + 5, limit) ; else byte_zero(tmp + 5, 12) ; + if (!skaclient_sendv(&a->connection, v, 2, &skaclient_default_cb, &err, deadline, stamp)) + { + register int e = errno ; + gensetdyn_delete(&a->q, i) ; + errno = e ; + return 0 ; + } + if (err) + { + gensetdyn_delete(&a->q, i) ; + return (errno = err, 0) ; + } + *GENSETDYN_P(skadnsanswer_t, &a->q, i) = skadnsanswer_initial ; + *u = i ; + return 1 ; +} diff --git a/src/skadns/skadns_start.c b/src/skadns/skadns_start.c new file mode 100644 index 0000000..3dccb54 --- /dev/null +++ b/src/skadns/skadns_start.c @@ -0,0 +1,10 @@ +/* ISC license. */ + +#include <skalibs/tai.h> +#include <skalibs/skaclient.h> +#include <s6-dns/skadns.h> + +int skadns_start (skadns_t *a, char const *path, tain_t const *deadline, tain_t *stamp) +{ + return skaclient_start_b(&a->connection, &a->buffers, path, SKADNS_BANNER1, SKADNS_BANNER1_LEN, SKADNS_BANNER2, SKADNS_BANNER2_LEN, deadline, stamp) ; +} diff --git a/src/skadns/skadns_startf.c b/src/skadns/skadns_startf.c new file mode 100644 index 0000000..ac19a0c --- /dev/null +++ b/src/skadns/skadns_startf.c @@ -0,0 +1,12 @@ +/* ISC license. */ + +#include <skalibs/environ.h> +#include <skalibs/tai.h> +#include <skalibs/skaclient.h> +#include <s6-dns/skadns.h> + +int skadns_startf (skadns_t *a, tain_t const *deadline, tain_t *stamp) +{ + static char const *const cargv[2] = { SKADNSD_PROG, 0 } ; + return skaclient_startf_b(&a->connection, &a->buffers, cargv[0], cargv, (char const *const *)environ, SKACLIENT_OPTION_WAITPID, SKADNS_BANNER1, SKADNS_BANNER1_LEN, SKADNS_BANNER2, SKADNS_BANNER2_LEN, deadline, stamp) ; +} diff --git a/src/skadns/skadns_update.c b/src/skadns/skadns_update.c new file mode 100644 index 0000000..50f3611 --- /dev/null +++ b/src/skadns/skadns_update.c @@ -0,0 +1,45 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/error.h> +#include <skalibs/uint16.h> +#include <skalibs/alloc.h> +#include <skalibs/bytestr.h> +#include <skalibs/genalloc.h> +#include <skalibs/gensetdyn.h> +#include <skalibs/unixmessage.h> +#include <skalibs/skaclient.h> +#include <s6/skadns.h> + +static int msghandler (unixmessage_t const *m, void *context) +{ + skadns_t *a = (skadns_t *)context ; + skadnsanswer_t *p ; + uint16 id ; + if (m->len < 3 || m->nfds) return (errno = EPROTO, 0) ; + uint16_unpack_big(m->s, &id) ; + p = GENSETDYN_P(skadnsanswer_t, &a->q, id) ; + if (p->status == ECANCELED) + { + p->status = EINVAL ; + return gensetdyn_delete(&a->q, id) ; + } + if (!error_isagain(p->status)) return (errno = EINVAL, 0) ; + if (!genalloc_readyplus(uint16, &a->list, 1)) return 0 ; + if (!m->s[2]) + { + p->data = alloc(m->len-3) ; + if (!p->data) return 0 ; + byte_copy(p->data, m->len-3, m->s+3) ; + p->len = m->len-3 ; + } + p->status = m->s[2] ; + genalloc_append(uint16, &a->list, &id) ; + return 1 ; +} + +int skadns_update (skadns_t *a) +{ + genalloc_setlen(uint16, &a->list, 0) ; + return skaclient_update(&a->connection, &msghandler, a) ; +} diff --git a/src/skadns/skadns_zero.c b/src/skadns/skadns_zero.c new file mode 100644 index 0000000..1842d2e --- /dev/null +++ b/src/skadns/skadns_zero.c @@ -0,0 +1,5 @@ +/* ISC license. */ + +#include <s6-dns/skadns.h> + +skadns_t const skadns_zero = SKADNS_ZERO ; diff --git a/src/skadns/skadnsd.c b/src/skadns/skadnsd.c new file mode 100644 index 0000000..7b5419f --- /dev/null +++ b/src/skadns/skadnsd.c @@ -0,0 +1,199 @@ +/* ISC license. */ + +#include <errno.h> +#include <signal.h> +#include <skalibs/uint16.h> +#include <skalibs/error.h> +#include <skalibs/strerr2.h> +#include <skalibs/sig.h> +#include <skalibs/tai.h> +#include <skalibs/djbunix.h> +#include <skalibs/iopause.h> +#include <skalibs/unixmessage.h> +#include <skalibs/skaclient.h> +#include <s6-dns/s6dns.h> +#include <s6-dns/skadns.h> + +typedef struct dnsio_s dnsio_t, *dnsio_t_ref ; +struct dnsio_s +{ + unsigned int xindex ; + s6dns_engine_t dt ; + uint16 id ; +} ; +#define DNSIO_ZERO { .xindex = SKADNS_MAXCONCURRENCY, .dt = S6DNS_ENGINE_ZERO, .id = 0 } + +static dnsio_t a[SKADNS_MAXCONCURRENCY] ; +static unsigned int sp = 0 ; + +static void remove (unsigned int i) +{ + dnsio_t tmp ; + tmp = a[sp-1] ; + a[--sp] = a[i] ; + a[i] = tmp ; +} + +static void fail (unsigned int i) +{ + char pack[3] ; + unixmessage_t m = { .s = pack, len = 3, .fds = 0, .nfds = 0 } ; + uint16_pack_big(pack, a[i].id) ; + pack[2] = a[i].dt.status ; + s6dns_engine_recycle(&a[i].dt) ; + remove(i) ; + if (!unixmessage_put(unixmessage_sender_x, &m)) + strerr_diefu1sys(111, "unixmessage_put") ; +} + +static void answer (char c) +{ + unixmessage_t m = { .s = &c, .len = 1, .fds = 0, .nfds = 0 } ; + if (!unixmessage_put(unixmessage_sender_1, &m)) + strerr_diefu1sys(111, "unixmessage_put") ; +} + +static int parse_protocol (unixmessage_t const *m, void *context) +{ + uint16 id ; + if (m->len < 3 || m->nfds) strerr_dief1x(100, "invalid client request") ; + uint16_unpack_big(m->s, &id) ; + switch (m->s[2]) /* protocol parsing */ + { + case 'Q' : /* send a query */ + { + tain_t limit ; + uint16 qtype ; + if (m->len < 21) strerr_dief1x(100, "invalid client request") ; + if (sp >= SKADNS_MAXCONCURRENCY) + { + answer(ENFILE) ; + break ; + } + uint16_unpack_big(m->s + 3, &qtype) ; + if (byte_diff(m->s + 5, 12, "\0\0\0\0\0\0\0\0\0\0\0")) + tain_unpack(m->s + 5, &limit) ; + else tain_add_g(&limit, &tain_infinite_relative) ; + if (!s6dns_engine_init_g(&a[sp].dt, &s6dns_rci_here.servers, 1, m->s + 17, m->len - 17, qtype, &limit)) + { + answer(errno) ; + break ; + } + a[sp++].id = id ; + answer(0) ; + break ; + } + case 'q' : /* cancel a query */ + { + register unsigned int i = 0 ; + for (; i < sp ; i++) if (a[i].id == id) break ; + if (i >= sp) + { + answer(ENOENT) ; + break ; + } + s6dns_engine_recycle(&a[i].dt) ; + remove(i) ; + answer(0) ; + break ; + } + default : strerr_dief1x(100, "invalid client request") ; + } + (void)context ; + return 1 ; +} + +int main (void) +{ + PROG = "skadnsd" ; + + if (ndelay_on(0) < 0) strerr_diefu2sys(111, "ndelay_on ", "0") ; + if (ndelay_on(1) < 0) strerr_diefu2sys(111, "ndelay_on ", "1") ; + if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; + tain_now_g() ; + if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ; + + { + tain_t deadline ; + tain_addsec_g(&deadline, 2) ; + if (!skaclient_server_01x_init_g(SKADNS_BANNER1, SKADNS_BANNER1_LEN, SKADNS_BANNER2, SKADNS_BANNER2_LEN, &deadline)) + strerr_diefu1sys(111, "sync with client") ; + } + { + static dnsio_t const zero = DNSIO_ZERO ; + register unsigned int i = 0 ; + for (; i < SKADNS_MAXCONCURRENCY ; i++) a[i] = zero ; + } + + for (;;) + { + iopause_fd x[3 + sp] ; + register int r ; + + x[0].fd = 0 ; x[0].events = IOPAUSE_EXCEPT | IOPAUSE_READ ; + x[1].fd = 1 ; x[1].events = IOPAUSE_EXCEPT | (unixmessage_sender_isempty(unixmessage_sender_1) ? 0 : IOPAUSE_WRITE) ; + x[2].fd = unixmessage_sender_fd(unixmessage_sender_x) ; + x[2].events = IOPAUSE_EXCEPT | (unixmessage_sender_isempty(unixmessage_sender_x) ? 0 : IOPAUSE_WRITE) ; + { + tain_t deadline = TAIN_INFINITE ; + register unsigned int i = 0 ; + for (; i < sp ; i++) + { + register unsigned int j = 3 + i ; + s6dns_engine_nextdeadline(&a[i].dt, &deadline) ; + x[j].fd = a[i].dt.fd ; + x[j].events = 0 ; + if (s6dns_engine_isreadable(&a[i].dt)) x[j].events |= IOPAUSE_READ ; + if (s6dns_engine_iswritable(&a[i].dt)) x[j].events |= IOPAUSE_WRITE ; + a[i].xindex = j ; + } + r = iopause_g(x, 3 + sp, &deadline) ; + } + if (r < 0) strerr_diefu1sys(111, "iopause") ; + if (!r) + { + register unsigned int i = 0 ; + for (; i < sp ; i++) + if (s6dns_engine_timeout_g(&a[i].dt)) fail(i--) ; + continue ; + } + + if (x[1].revents & IOPAUSE_WRITE) + if ((unixmessage_sender_flush(unixmessage_sender_1) < 0) && !error_isagain(errno)) + strerr_diefu1sys(111, "flush stdout") ; + if (x[2].revents & IOPAUSE_WRITE) + if ((unixmessage_sender_flush(unixmessage_sender_x) < 0) && !error_isagain(errno)) + strerr_diefu1sys(111, "flush asyncout") ; + + { + register unsigned int i = 0 ; + for (; i < sp ; i++) if (x[a[i].xindex].revents) + { + register int r = s6dns_engine_event_g(&a[i].dt) ; + if (r < 0) fail(i--) ; + else if (r) + { + char pack[3] ; + siovec_t v[2] = { { .s = pack, .len = 3 }, { .s = s6dns_engine_packet(&a[i].dt), .len = s6dns_engine_packetlen(&a[i].dt) } } ; + unixmessage_v_t mv = { .v = v, .vlen = 2, .fds = 0, .nfds = 0 } ; + uint16_pack_big(pack, a[i].id) ; + pack[2] = 0 ; + if (!unixmessage_putv(unixmessage_sender_x, v, 2)) + strerr_diefu1sys(111, "unixmessage_put") ; + s6dns_engine_recycle(&a[i].dt) ; + remove(i--) ; + } + } + } + + if (!unixmessage_receiver_isempty(unixmessage_receiver_0) || x[0].revents & IOPAUSE_READ) + { + if (unixmessage_handle(unixmessage_receiver_0, &parse_protocol, 0) < 0) + { + if (errno == EPIPE) break ; /* normal exit */ + strerr_diefu1sys(111, "handle messages from client") ; + } + } + } + return 0 ; +} |