diff options
| author | Laurent Bercot <ska-skaware@skarnet.org> | 2026-02-06 02:16:08 +0000 |
|---|---|---|
| committer | Laurent Bercot <ska-skaware@skarnet.org> | 2026-02-06 02:16:08 +0000 |
| commit | 5ca4a0e5b65066f41af7c670e8200b0d0eba41dd (patch) | |
| tree | 76f0fdef194f6227f4903d9139157a76b18f936e /src/qmail-smtpc/dns.c | |
| parent | 025de935255c05d72a5c35d86c6c5c4d212247a1 (diff) | |
| download | smtpd-starttls-proxy-5ca4a0e5b65066f41af7c670e8200b0d0eba41dd.tar.gz | |
Just name it qmail-remote after all
Diffstat (limited to 'src/qmail-smtpc/dns.c')
| -rw-r--r-- | src/qmail-smtpc/dns.c | 315 |
1 files changed, 0 insertions, 315 deletions
diff --git a/src/qmail-smtpc/dns.c b/src/qmail-smtpc/dns.c deleted file mode 100644 index 90aade4..0000000 --- a/src/qmail-smtpc/dns.c +++ /dev/null @@ -1,315 +0,0 @@ -/* ISC license. */ - -#include <string.h> -#include <stdint.h> -#include <limits.h> -#include <stdlib.h> -#include <errno.h> - -#include <skalibs/tai.h> -#include <skalibs/stralloc.h> -#include <skalibs/genalloc.h> -#include <skalibs/iopause.h> -#include <skalibs/ip46.h> -#include <skalibs/random.h> - -#include <s6-dns/s6dns.h> -#include <s6-dns/skadns.h> - -#include "qmailr.h" -#include "qmail-smtpc.h" - -typedef struct cnameinfo_s cnameinfo, *cnameinfo_ref ; -struct cnameinfo_s -{ - stralloc sa ; - size_t atpos ; - uint16_t id ; - uint16_t count ; -} ; - -typedef struct mxipinfo_s mxipinfo, mxipinfo_ref ; -struct mxipinfo_s -{ - stralloc ip4 ; - stralloc ip6 ; - uint16_t id4 ; - uint16_t id6 ; -} ; -#define MXIPINFO_ZERO { .ip4 = STRALLOC_ZERO, .ip6 = STRALLOC_ZERO, .id4 = UINT16_MAX, .id6 = UINT16_MAX } - -static int mx_cmp (void const *a, void const *b) -{ - s6dns_message_rr_mx_t const *aa = a ; - s6dns_message_rr_mx_t const *bb = b ; - return aa->preference < bb-> preference ? -1 : aa->preference > bb->preference ; -} - -static unsigned int use_host_as_mx (skadns_t *a, char const *host, genalloc *mxip, tain const *deadline) -{ - unsigned int newreqs = 0 ; - mxipinfo info = MXIPINFO_ZERO ; - s6dns_domain_t q ; - if (!s6dns_domain_fromstring_noqualify_encode(&q, host, strlen(host))) - qmailr_tempsys("Unable to DNS-encode host domain") ; - if (!skadns_send_g(a, &info.id4, &q, S6DNS_T_A, deadline, deadline)) - qmailr_tempsys("Unable to send A DNS query") ; - newreqs++ ; -#ifdef SKALIBS_IPV6_ENABLED - if (!skadns_send_g(a, &info.id6, &q, S6DNS_T_AAAA, deadline, deadline)) - qmailr_tempsys("Unable to send AAAA DNS query") ; - newreqs++ ; -#endif - if (!genalloc_catb(mxipinfo, mxip, &info, 1)) dienomem() ; - return newreqs ; -} - - /* - The point of this monster here is to do all the DNS resolutions in parallel, - to avoid compounding network latency. One of the many things that could never - be done by patching qmail-remote. - 1 sender + n-1 recipients are given in eaddr. - - loop around CNAME until we get the canonical name, for the n eaddrs - - either lookup the MX for the host then find all the A and AAAAs of all the MXes, - or get the A and AAAAs of the host directly (if smtproutes) - - do not keep the As and AAAAs listed in ipme - - sort the set of IPs by MX preference - When done, quote all the boxnames in eaddr. - Shove everything in storage and return the indices: - in eaddrpos for sender+recipients, in mxipind for the IPs to connect to. - - Also, fuck DNS for requiring so many small allocations and data copies. - - Also, fuck DNS. - */ - -void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size_t *eaddrpos, genalloc *mxipind, stralloc *storage, unsigned int timeoutdns, char const *ipme4, unsigned int n4, char const *ipme6, unsigned int n6, uint32_t flags) -{ - skadns_t a = SKADNS_ZERO ; - genalloc mxipi = GENALLOC_ZERO ; /* mxipinfo */ - tain deadline ; - unsigned int pending = 0 ; - uint16_t mxn = 0 ; - uint16_t mxid = UINT16_MAX ; - cnameinfo cnames[n] ; - - tain_addsec_g(&deadline, timeoutdns) ; - if (!skadns_startf_g(&a, &deadline)) - qmailr_tempsys("Unable to start asynchronous DNS helper") ; - - for (unsigned int i = 0 ; i < n ; i++) - { - char const *at = strrchr(eaddr[i], '@') ; - cnames[i].sa = stralloc_zero ; - if (at) - { - s6dns_domain_t q ; - size_t len = strlen(at+1) ; - cnames[i].atpos = at - eaddr[i] ; - if (!stralloc_catb(&cnames[i].sa, at+1, len)) dienomem() ; - if (!s6dns_domain_fromstring_noqualify_encode(&q, at+1, len)) - qmailr_tempsys("Unable to DNS-encode recipient domain") ; - if (!skadns_send_g(&a, &cnames[i].id, &q, S6DNS_T_CNAME, &deadline, &deadline)) - qmailr_tempsys("Unable to send CNAME DNS query") ; - cnames[i].count = 1 ; - pending++ ; - } - else - { - cnames[i].id = UINT16_MAX ; - cnames[i].count = 0 ; - cnames[i].atpos = strlen(eaddr[i]) ; - } - } - - if (flags & 1) - { - s6dns_domain_t q ; - if (!s6dns_domain_fromstring_noqualify_encode(&q, host, strlen(host))) - qmailr_tempsys("Unable to DNS-encode host domain") ; - if (!skadns_send_g(&a, &mxid, &q, S6DNS_T_MX, &deadline, &deadline)) - qmailr_tempsys("Unable to send MX DNS query") ; - pending++ ; - } - else - { - mxn = 1 ; - pending += use_host_as_mx(&a, host, &mxipi, &deadline) ; - } - - while (pending) - { - uint16_t *ids ; - iopause_fd x = { .fd = skadns_fd(&a), .events = IOPAUSE_READ } ; - int r = iopause_g(&x, 1, &deadline) ; - if (r == -1) qmailr_tempsys("Unable to iopause") ; - if (!r) qmailr_tempsys("Timed out waiting for DNS") ; - r = skadns_update(&a) ; - if (r == -1) qmailr_tempsys("Unable to read DNS answers") ; - ids = genalloc_s(uint16_t, &a.list) ; - for (size_t j = 0 ; j < genalloc_len(uint16_t, &a.list) ; j++) - { - char const *packet = skadns_packet(&a, ids[j]) ; - uint16_t packetlen = skadns_packetlen(&a, ids[j]) ; - if (!packet) qmailr_tempsys("DNS packet reading error") ; - - if (ids[j] == mxid) /* return from MX query */ - { - s6dns_message_header_t h ; - genalloc mxes = GENALLOC_ZERO ; /* s6dns_message_rr_mx_t */ - r = s6dns_message_parse(&h, packet, packetlen, &s6dns_message_parse_answer_mx, &mxes) ; - if (r == -1) qmailr_tempsys("DNS packet parsing error") ; - if (!r) - { - if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving MX") ; - else qmailr_perm("DNS CNAME resolution error") ; - } - skadns_release(&a, ids[j]) ; - pending-- ; - mxid = UINT16_MAX ; - if (r >= 2) /* we have MXes, ask for their IPs */ - { - s6dns_message_rr_mx_t *mxs = genalloc_s(s6dns_message_rr_mx_t, &mxes) ; - mxn = genalloc_len(s6dns_message_rr_mx_t, &mxes) ; - if (!genalloc_readyplus(mxipinfo, &mxipi, mxn)) dienomem() ; - qsort(mxs, mxn, sizeof(s6dns_message_rr_mx_t), &mx_cmp) ; - for (unsigned int i = 0 ; i < mxn ; i++) - { - mxipinfo *p = genalloc_s(mxipinfo, &mxipi) + i ; - p->ip4 = p->ip6 = stralloc_zero ; - if (!skadns_send_g(&a, &p->id4, &mxs[i].exchange, S6DNS_T_A, &deadline, &deadline)) - qmailr_tempsys("Unable to send A DNS query") ; - pending++ ; -#ifdef SKALIBS_IPV6_ENABLED - if (!skadns_send_g(&a, &p->id6, &mxs[i].exchange, S6DNS_T_AAAA, &deadline, &deadline)) - qmailr_tempsys("Unable to send AAAA DNS query") ; - pending++ ; -#endif - } - genalloc_free(s6dns_message_rr_mx_t, &mxes) ; - } - else - { - mxn = 1 ; - pending += use_host_as_mx(&a, host, &mxipi, &deadline) ; - } - continue ; - } - - for (unsigned int i = 0 ; i < n ; i++) if (ids[j] == cnames[i].id) /* return from CNAME query */ - { - s6dns_message_header_t h ; - s6dns_dpag_t dlist = { .ds = GENALLOC_ZERO, .rtype = S6DNS_T_CNAME } ; - r = s6dns_message_parse(&h, packet, packetlen, &s6dns_message_parse_answer_domain, &dlist) ; - if (r == -1) qmailr_tempsys("DNS packet parsing error") ; - if (!r) - { - if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving CNAME") ; - else qmailr_perm("DNS CNAME resolution error") ; - } - skadns_release(&a, ids[j]) ; - pending-- ; - if (r >= 2) /* it's a CNAME, loop on it */ - { - s6dns_domain_t *domain = genalloc_s(s6dns_domain_t, &dlist.ds) ; - if (cnames[i].count++ >= 100) qmailr_temp("DNS CNAME loop") ; - if (!skadns_send_g(&a, &cnames[i].id, domain, S6DNS_T_CNAME, &deadline, &deadline)) - qmailr_tempsys("Unable to send CNAME DNS query") ; - pending++ ; - if (!stralloc_ready(&cnames[i].sa, 256)) dienomem() ; - s6dns_domain_decode(domain) ; - cnames[i].sa.len = s6dns_domain_tostring(cnames[i].sa.s, 256, domain) ; - genalloc_free(s6dns_domain_t, &dlist.ds) ; - } - else cnames[i].id = UINT16_MAX ; /* that's the canonical host in cnames[i].sa */ - continue ; - } - - for (unsigned int i = 0 ; i < mxn ; i++) - { - mxipinfo *p = genalloc_s(mxipinfo, &mxipi) + i ; - if (ids[j] == p->id4) - { - s6dns_message_header_t h ; - r = s6dns_message_parse(&h, packet, packetlen, &s6dns_message_parse_answer_a, &p->ip4) ; - if (r == -1) qmailr_tempsys("DNS packet parsing error") ; - if (!r) - { - if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving A") ; - else qmailr_perm("DNS A resolution error") ; - } - skadns_release(&a, ids[j]) ; - pending-- ; - p->id4 = UINT16_MAX ; - for (unsigned int k = 0 ; k < p->ip4.len ; k += 4) - { - if (bsearch(p->ip4.s + k, ipme4, n4, 4, &qmailr_memcmp4)) - { - memmove(p->ip4.s + k, p->ip4.s + p->ip4.len - 4, 4) ; - p->ip4.len -= 4 ; - k -= 4 ; - } - } - } -#ifdef SKALIBS_IPV6_ENABLED - else if (ids[j] == p->id6) - { - s6dns_message_header_t h ; - r = s6dns_message_parse(&h, packet, packetlen, &s6dns_message_parse_answer_aaaa, &p->ip6) ; - if (r == -1) qmailr_tempsys("DNS packet parsing error") ; - if (!r) - { - if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving AAAA") ; - else qmailr_perm("DNS AAAA resolution error") ; - } - skadns_release(&a, ids[j]) ; - pending-- ; - p->id6 = UINT16_MAX ; - for (unsigned int k = 0 ; k < p->ip6.len ; k += 16) - { - if (bsearch(p->ip6.s + k, ipme6, n6, 16, &qmailr_memcmp16)) - { - memmove(p->ip6.s + k, p->ip6.s + p->ip6.len - 16, 16) ; - p->ip6.len -= 16 ; - k -= 16 ; - } - } - } -#endif - } - } - } - skadns_end(&a) ; /* we done buddy */ - - for (unsigned int i = 0 ; i < n ; i++) - { - eaddrpos[i] = storage->len ; - if (!qmailr_box_encode(eaddr[i], cnames[i].atpos, storage)) dienomem() ; - if (cnames[i].count) - { - if (!stralloc_catb(storage, "@", 1)) dienomem() ; - if (!stralloc_catb(storage, cnames[i].sa.s, cnames[i].sa.len)) dienomem() ; - stralloc_free(&cnames[i].sa) ; - } - if (!stralloc_0(storage)) dienomem() ; - } - - if (!genalloc_readyplus(mxip, mxipind, mxn)) dienomem() ; - for (unsigned int i = 0 ; i < mxn ; i++) - { - mxip data ; - mxipinfo *p = genalloc_s(mxipinfo, &mxipi) + i ; - data.n4 = p->ip4.len >> 2 ; - data.pos4 = storage->len ; - if (!stralloc_catb(storage, p->ip4.s, p->ip4.len)) dienomem() ; - stralloc_free(&p->ip4) ; -#ifdef SKALIBS_IPV6_ENABLED - data.n6 = p->ip6.len >> 4 ; - data.pos6 = storage->len ; - if (!stralloc_catb(storage, p->ip6.s, p->ip6.len)) dienomem() ; - stralloc_free(&p->ip6) ; - genalloc_catb(mxip, mxipind, &data, 1) ; -#endif - } - genalloc_free(mxipinfo, &mxipi) ; -} |
