From 696792f08106e5bea4a8847e394401c1a68ecf9c Mon Sep 17 00:00:00 2001 From: manuel Date: Mon, 7 Aug 2023 16:33:27 +0200 Subject: add dns_tlsa(...) and dnstlsa utility --- Makefile | 14 ++++++++- dns.c | 41 ++++++++++++++++++++++++++ dns.h | 3 ++ dnstlsa.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 dnstlsa.c diff --git a/Makefile b/Makefile index 595f47b..fa5c282 100644 --- a/Makefile +++ b/Makefile @@ -479,6 +479,18 @@ compile dnsptr.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \ str.h scan.h dns.h dnsdoe.h ip.h exit.h ./compile dnsptr.c +dnstlsa: \ +load dnstlsa.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \ +substdio.a error.a str.a fs.a dns.lib socket.lib + ./load dnstlsa dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \ + alloc.a substdio.a error.a str.a fs.a `cat dns.lib` `cat \ + socket.lib` getopt.a + +dnstlsa.o: \ +compile dnstlsa.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \ +str.h scan.h dns.h dnsdoe.h ip.h exit.h + ./compile dnstlsa.c + dot-qmail.0: \ dot-qmail.5 nroff -man dot-qmail.5 > dot-qmail.0 @@ -812,7 +824,7 @@ predate datemail mailsubj qmail-upq qmail-showctl qmail-newu \ qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-tcpok \ qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \ qmail-smtpd sendmail tcp-env qmail-newmrh qmail-newbrt config config-fast dnscname \ -dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \ +dnsptr dnsip dnsmxip dnsfq dnstlsa hostname ipmeprint qreceipt qsmhook qbiff \ forward preline condredirect bouncesaying except maildirmake \ maildir2mbox maildirwatch qail elq pinq idedit install-big install \ instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \ diff --git a/dns.c b/dns.c index bed2bd2..b4d106c 100644 --- a/dns.c +++ b/dns.c @@ -418,3 +418,44 @@ unsigned long random; alloc_free(mx); return flagsoft; } + +int dns_tlsa(stralloc *out, const stralloc *fqdn) +{ + int ranswers = 0; + + switch(resolve(fqdn, T_TLSA)) + { + case DNS_MEM: return DNS_MEM; + case DNS_SOFT: return DNS_SOFT; + case DNS_HARD: return DNS_HARD; + } + + if (!stralloc_copys(out,"")) return DNS_MEM; + while(numanswers-- > 0) { + int i; + if (responsepos == responseend) return DNS_SOFT; + + i = dn_expand(response.buf, responseend, responsepos, name, MAXDNAME); + if (i < 0) return DNS_SOFT; + responsepos += i; + + i = responseend - responsepos; + if (i < 4 + 3 * 2) return DNS_SOFT; + + unsigned short rrtype = getshort(responsepos); + unsigned short rrdlen = getshort(responsepos + 8); + responsepos += 10; // skip dns header + if (responsepos + rrdlen > responseend) return DNS_HARD; + + if (rrtype == T_TLSA) + { + unsigned char rrlen[2] = { rrdlen >> 8, rrdlen & 0xFF }; + stralloc_catb(out, rrlen, 2); + if (!stralloc_catb(out, responsepos, rrdlen)) return DNS_MEM; + ++ranswers; + } + + responsepos += rrdlen; + } + return ranswers; +} diff --git a/dns.h b/dns.h index bca9490..08534a2 100644 --- a/dns.h +++ b/dns.h @@ -1,6 +1,8 @@ #ifndef DNS_H #define DNS_H +#include "stralloc.h" + #define DNS_SOFT -1 #define DNS_HARD -2 #define DNS_MEM -3 @@ -10,5 +12,6 @@ int dns_cname(); int dns_mxip(); int dns_ip(); int dns_ptr(); +int dns_tlsa(stralloc *out, const stralloc *fqdn); #endif diff --git a/dnstlsa.c b/dnstlsa.c new file mode 100644 index 0000000..6623cfd --- /dev/null +++ b/dnstlsa.c @@ -0,0 +1,99 @@ +#include +#include "byte.h" +#include "substdio.h" +#include "subfd.h" +#include "subgetopt.h" +#include "stralloc.h" +#include "dns.h" +#include "dnsdoe.h" +#include "exit.h" + +stralloc sa = {0}; +stralloc out = {0}; + +static void die_nomem() +{ + substdio_putsflush(subfderr, "out of memory\n"); + _exit(111); +} + + #include +void main(int argc, char **argv) +{ + char *port = "25"; + char proto[7] = "._tcp."; + char *host = NULL; + int opt; + int verbose = 0; + + while ((opt = sgopt(argc, argv, "vutp:")) != sgoptdone) + { + switch(opt) + { + case 'p': port = sgoptarg; break; + case 't': break; + case 'u': byte_copy(proto, 6, "._udp."); break; + case 'v': verbose = 1; + } + } + + argv += sgoptind; + argc -= sgoptind; + + if (!argv[0]) + { + substdio_putsflush(subfderr, "dnstlsa [-v] [-p port] [-u(dp)|-t(cp)] host (tcp on port 25 is default)\n"); + _exit(100); + } + host = argv[0]; + + if (!stralloc_copyb(&sa, "_", 1)) die_nomem; + if (!stralloc_cats(&sa, port)) die_nomem; + if (!stralloc_cats(&sa, proto)) die_nomem; + if (!stralloc_cats(&sa, host)) die_nomem; + + if (verbose) + { + substdio_puts(subfdout, "checking for TLSA records: "); + substdio_put(subfdout, sa.s, sa.len); + substdio_putsflush(subfdout, "\n"); + } + + dns_init(0); + dnsdoe(dns_tlsa(&out, &sa)); + + int pos = 0; + unsigned char *response = (unsigned char *)out.s; + while(pos < out.len && out.len - pos > 2 + 4) // sizeof(rrlen) + min(rrdata) + { + unsigned short rrlen = (response[pos] << 8) + response[pos + 1]; + pos += 2; + uint8_t usage = response[pos]; + uint8_t sel = response[pos + 1]; + uint8_t type = response[pos + 2]; + + if (usage == 0) substdio_puts(subfdout, "usage=0 "); + if (usage == 1) substdio_puts(subfdout, "usage=1 "); + if (usage == 2) substdio_puts(subfdout, "usage=2 "); + if (usage == 3) substdio_puts(subfdout, "usage=3 "); + + if (sel == 0) substdio_puts(subfdout, "selector=0 "); + if (sel == 1) substdio_puts(subfdout, "selector=1 "); + + if (type == 0) substdio_puts(subfdout, "type=0 "); // full cert + if (type == 1) substdio_puts(subfdout, "type=1 "); // sha256 + if (type == 2) substdio_puts(subfdout, "type=2 "); // sha512 + + substdio_puts(subfdout, "data="); // sha512 + for (int j = 3; j < rrlen; j++) + { + unsigned char ch = response[pos + j]; + substdio_put(subfdout, "0123456789abcdef" + (ch >> 4), 1); + substdio_put(subfdout, "0123456789abcdef" + (ch & 0x0F), 1); + } + substdio_putsflush(subfdout, "\n"); + pos += rrlen; + } + + _exit(0); +} -- cgit v1.2.3