From 36491e787c8be5b32b93f5c3b20edd9aa9d4c4e9 Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Mon, 2 Feb 2026 18:01:03 +0000 Subject: More qmail-smtpc stuff --- src/qmail-smtpc/dns.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 src/qmail-smtpc/dns.c (limited to 'src/qmail-smtpc/dns.c') diff --git a/src/qmail-smtpc/dns.c b/src/qmail-smtpc/dns.c new file mode 100644 index 0000000..a469019 --- /dev/null +++ b/src/qmail-smtpc/dns.c @@ -0,0 +1,177 @@ +/* ISC license. */ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "qmailr.h" +#include "qmail-smtpc.h" + +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 ; +} + +void dns_init (void) +{ + if (!s6dns_init_options(0)) qmail_tempsys("Unable to init DNS") ; +} + +void dns_canon (char const *host, char const *const *recip, unsigned int n, size_t *recippos, genalloc *mxpos, stralloc *storage) +{ + genalloc mx = GENALLOC_ZERO ; /* s6dns_message_rr_mx_t */ + size_t atpos[n] ; + s6dns_dpag_t cnames[n] ; + s6dns_resolve_t info[n + !!mxpos] ; + + for (unsigned int i = 0 ; i < n ; i++) + { + char const *at = strrchr(recip[i], '@') ; + if (!at) qmailr_perm("Invalid recipient") ; + atpos[i] = at - recip[i] ; + if (!s6dns_domain_fromstring_noqualify_encode(&info[i].q, at+1, strlen(at+1)) + qmailr_tempsys("Unable to DNS-encode recipient domain") ; + cnames[i].ds = genalloc_zero ; + cnames[i].rtype = S6DNS_T_CNAME ; + info[i].qtype = S6DNS_T_CNAME ; + info[i].options = S6DNS_O_RECURSIVE ; + info[i].deadline = tain_infinite ; + info[i].parsefunc = &s6dns_message_parse_answer_domain ; + info[i].data = cnames + i ; + } + if (!s6dns_domain_fromstring_noqualify_encode(&info[n].q, host, strlen(host)) + qmailr_tempsys("Unable to DNS-encode recipient domain") ; + + if (mxpos) + { + info[n].qtype = S6DNS_T_MX ; + info[n].options = S6DNS_O_RECURSIVE ; + info[n].deadline = tain_infinite ; + info[n].parsefunc = &s6dns_message_parse_answer_mx ; + info[n].data = &mx ; + } + + if (!s6dns_resolven_parse_g(info, n + !!mxpos, 0)) + qmailr_tempsys("Unable to perform DNS resolutions") ; + + for (unsigned int i = 0 ; i < n ; i++) + { + recippos[i] = storage->len ; + box_encode(recip[i], atpos[i], storage) ; + if (!stralloc_catb(storage, "@", 1)) dienomem() ; + if (!info[i].status && genalloc_len(s6dns_domain_t, &cnames[i].ds)) + { + if (!s6dns_domain_decode(genalloc_s(s6dns_domain_t, &cnames[i].ds)) + qmailr_tempsys("Unable to parse CNAME") ; + if (!stralloc_readyplus(storage, 256)) dienomem() ; + recippos[i] = storage->len ; + storage->len += s6dns_domain_tostring(storage->s + storage->len, 255, genalloc_s(s6dns_domain_t, &cnames[i].ds)) ; + if (storage->s[storage->len-1] == '.') --storage->len ; + storage->s[storage->len++] = 0 ; + } + else if (!stralloc_cats(storage, recip[i] + atpos[i] + 1)) dienomem() ; + if (!stralloc_0(storage)) dienomem() ; + } + + if (mxpos && !info[n].status && genalloc_len(s6dns_message_rr_mx_t, &mx)) + { + s6dns_message_rr_mx_t *mxs = genalloc_s(s6dns_message_rr_mx_t, &mx) ; + size_t mxlen = genalloc_len(s6dns_message_rr_mx_t, &mx) ; + qsort(mxs, mxlen, sizeof(s6dns_message_rr_mx_t), &mx_cmp) ; + if (!genalloc_readyplus(size_t, mxpos, mxlen)) dienomem() ; + for (size_t i = 0 ; i < mxlen ; i++) + { + if (!s6dns_domain_decode(&mxs[i].exchange)) qmailr_tempsys("Unable to parse MX record") ; + if (!stralloc_readyplus(storage, 256)) dienomem() ; + genalloc_catb(size_t, mxpos, storage->len) ; + storage->len += s6dns_domain_tostring(storage->s + storage->len, 255, &mxs[i].exchange) ; + storage->s[storage->len++] = 0 ; + } + genalloc_free(s6dns_message_rr_mx_t, &mx) ; + } +} + +void dns_ip_of_mx (size_t const *pos, unsigned int n, mxip *tab, stralloc *storage, char const *ipme4, unsigned int n4, char const *ipme6, unsigned int n6) +{ +#ifdef SKALIBS_IPV6_ENABLED + unsigned int const N = n << 1 ; + stralloc ip6[n] ; +#else + unsigned int const N = n ; +#endif + stralloc ip4[n] ; + s6dns_resolve_t info[N] ; + for (unsigned int i = 0 ; i < n ; i++) + { + if (!s6dns_domain_fromstring_noqualify_encode(&info[i].q, storage->s + pos[i], strlen(storage->s + pos[i])) + qmailr_tempsys("Unable to DNS-encode MX") ; + ip4[i] = stralloc_zero ; + info[i].qtype = S6DNS_T_A ; + info[i].options = S6DNS_O_RECURSIVE ; + info[i].deadline = tain_infinite ; + info[i].parsefunc = &s6dns_message_parse_answer_a ; + info[i].data = ip4 + i ; + +#ifdef SKALIBS_IPV6_ENABLED + ip6[i] = stralloc_zero ; + info[n+i].q = info[i].q ; + info[n+i].qtype = S6DNS_T_A ; + info[n+i].options = S6DNS_O_RECURSIVE ; + info[n+i].deadline = tain_infinite ; + info[n+i].parsefunc = &s6dns_message_parse_answer_aaaa ; + info[n+i].data = ip6 + i ; +#endif + } + + if (!s6dns_resolven_parse_g(info, N, 0)) + qmailr_tempsys("Unable to perform DNS resolutions") ; + + for (unsigned int i = 0 ; i < n ; i++) + { + if (!info[i].status) + { + for (unsigned int j = 0 ; j < ip4[i].len ; j += 4) + { + if (bsearch(ip4.s + j, ipme4, n4, 4, &qmailr_memcmp4)) + { + memmove(ip4[i].s + j, ip4[i].s + ip4[i].len - 4, 4) ; + ip4[i].len -= 4 ; + } + } + random_unsort(ip4.s, ip4.len >> 2, 4) ; + tab[i].pos4 = storage->len ; + tab[i].n4 = ip4.len >> 2 ; + if (!stralloc_catb(&storage, ip4.s, ip4.len)) dienomem() ; + stralloc_free(ip4 + i) ; + } + +#ifdef SKALIBS_IPV6_ENABLED + if (!info[n+i].status) + { + for (unsigned int j = 0 ; j < ip6[i].len ; j += 16) + { + if (bsearch(ip6.s + j, ipme6, n6, 16, &qmailr_memcmp16)) + { + memmove(ip6[i].s + j, ip6[i].s + ip6[i].len - 16, 16) ; + ip6[i].len -= 16 ; + } + } + random_unsort(ip6.s, ip6.len >> 4, 16) ; + tab[i].pos6 = storage->len ; + tab[i].n6 = ip6.len >> 4 ; + if (!stralloc_catb(&storage, ip6.s, ip6.len)) dienomem() ; + stralloc_free(ip6 + i) ; + } +#endif + + } +} -- cgit v1.3.1