aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmail-smtpc
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2026-02-05 14:13:02 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2026-02-05 14:13:02 +0000
commit025de935255c05d72a5c35d86c6c5c4d212247a1 (patch)
treebb48c3b253192acf2818801c57adc239c74a1497 /src/qmail-smtpc
parent87664716d2c1c43e4386099e3ce3f4b11d56e76e (diff)
downloadsmtpd-starttls-proxy-025de935255c05d72a5c35d86c6c5c4d212247a1.tar.gz
Make all the DNS asynchronous
Diffstat (limited to 'src/qmail-smtpc')
-rw-r--r--src/qmail-smtpc/deps-exe/qmail-smtpc1
-rw-r--r--src/qmail-smtpc/dns.c378
-rw-r--r--src/qmail-smtpc/qmail-smtpc.c19
-rw-r--r--src/qmail-smtpc/qmail-smtpc.h4
-rw-r--r--src/qmail-smtpc/qmailr.h2
-rw-r--r--src/qmail-smtpc/qmailr_tls.c5
-rw-r--r--src/qmail-smtpc/qmailr_utils.c45
7 files changed, 317 insertions, 137 deletions
diff --git a/src/qmail-smtpc/deps-exe/qmail-smtpc b/src/qmail-smtpc/deps-exe/qmail-smtpc
index 5bb5360..4484f9b 100644
--- a/src/qmail-smtpc/deps-exe/qmail-smtpc
+++ b/src/qmail-smtpc/deps-exe/qmail-smtpc
@@ -1,5 +1,6 @@
dns.o
smtproutes.o
libqmailr.a.xyzzy
+-lskadns
-ls6dns
-lskarnet
diff --git a/src/qmail-smtpc/dns.c b/src/qmail-smtpc/dns.c
index 52ec552..90aade4 100644
--- a/src/qmail-smtpc/dns.c
+++ b/src/qmail-smtpc/dns.c
@@ -1,19 +1,43 @@
/* 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 ;
@@ -21,157 +45,271 @@ static int mx_cmp (void const *a, void const *b)
return aa->preference < bb-> preference ? -1 : aa->preference > bb->preference ;
}
-void dns_init (void)
+static unsigned int use_host_as_mx (skadns_t *a, char const *host, genalloc *mxip, tain const *deadline)
{
- if (!s6dns_init_options(0)) qmailr_tempsys("Unable to init DNS") ;
+ 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 ;
}
-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] ;
+ /*
+ 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.
- 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") ;
+ Also, fuck DNS for requiring so many small allocations and data copies.
- 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 ;
- }
+ Also, fuck DNS.
+ */
- if (!s6dns_resolven_parse_g(info, n + !!mxpos, 0))
- qmailr_tempsys("Unable to perform DNS resolutions") ;
+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++)
{
- recippos[i] = storage->len ;
- // TODO: 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))
+ char const *at = strrchr(eaddr[i], '@') ;
+ cnames[i].sa = stralloc_zero ;
+ if (at)
{
- 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 ;
+ 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]) ;
}
- 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))
+ if (flags & 1)
{
- 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, 1) ;
- 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) ;
+ 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) ;
}
-}
-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++)
+ while (pending)
{
- 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 ;
+ 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
- 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 ;
+ 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
- }
-
- if (!s6dns_resolven_parse_g(info, N, 0))
- qmailr_tempsys("Unable to perform DNS resolutions") ;
+ }
+ 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 (!info[i].status)
- {
- for (unsigned int j = 0 ; j < ip4[i].len ; j += 4)
+ for (unsigned int i = 0 ; i < n ; i++) if (ids[j] == cnames[i].id) /* return from CNAME query */
{
- if (bsearch(ip4[i].s + j, ipme4, n4, 4, &qmailr_memcmp4))
+ 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 */
{
- memmove(ip4[i].s + j, ip4[i].s + ip4[i].len - 4, 4) ;
- ip4[i].len -= 4 ;
+ 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 ;
}
- random_unsort(ip4[i].s, ip4[i].len >> 2, 4) ;
- tab[i].pos4 = storage->len ;
- tab[i].n4 = ip4[i].len >> 2 ;
- if (!stralloc_catb(storage, ip4[i].s, ip4[i].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)
+ for (unsigned int i = 0 ; i < mxn ; i++)
{
- if (bsearch(ip6[i].s + j, ipme6, n6, 16, &qmailr_memcmp16))
+ 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)
{
- memmove(ip6[i].s + j, ip6[i].s + ip6[i].len - 16, 16) ;
- ip6[i].len -= 16 ;
+ 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
}
- random_unsort(ip6[i].s, ip6[i].len >> 4, 16) ;
- tab[i].pos6 = storage->len ;
- tab[i].n6 = ip6[i].len >> 4 ;
- if (!stralloc_catb(storage, ip6[i].s, ip6[i].len)) dienomem() ;
- stralloc_free(ip6 + i) ;
}
-#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) ;
}
diff --git a/src/qmail-smtpc/qmail-smtpc.c b/src/qmail-smtpc/qmail-smtpc.c
index f194700..0e0b11b 100644
--- a/src/qmail-smtpc/qmail-smtpc.c
+++ b/src/qmail-smtpc/qmail-smtpc.c
@@ -25,7 +25,7 @@ int main (int argc, char const *const *argv)
smtproutes routes = SMTPROUTES_ZERO ;
unsigned int timeoutconnect = 60, timeoutremote = 1200 ;
char const *host ;
- size_t mepos, helopos, hostpos = 0, senderpos ;
+ size_t mepos, helopos, hostpos = 0 ;
uint16_t port = 25 ;
int r ;
@@ -35,7 +35,7 @@ int main (int argc, char const *const *argv)
if (sig_altignore(SIGPIPE) == -1) qmailr_tempsys("Unable to ignore SIGPIPE") ;
host = *argv++ ; argc-- ;
tain_now_set_stopwatch_g() ;
- dns_init() ;
+
/* init control */
@@ -74,20 +74,11 @@ int main (int argc, char const *const *argv)
smtproutes_free(&routes) ;
}
- // TODO: box_encode(&senderpos) ;
-
{
- genalloc mxpos = GENALLOC_ZERO ;
- int usehost ;
- size_t recippos[argc] ;
-
- dns_canon(host, argv, argc, recippos, hostpos ? 0 : &mxpos, &storage) ;
- usehost = hostpos || !genalloc_len(size_t, &mxpos) ;
+ genalloc mxipind = GENALLOC_ZERO ;
+ size_t eaddrpos[argc] ;
+ dns_stuff(hostpos ? storage.s + hostpos : host, argv, argc, eaddrpos, &mxipind, &storage, timeoutconnect, ipme4.s, ipme4.len >> 2, ipme6.s, ipme6.len >> 4, !hostpos) ;
- unsigned int mxn = usehost ? 1 : genalloc_len(size_t, &mxpos) ;
- mxip mxind[mxn] ;
- dns_ip_of_mx(usehost ? &hostpos : genalloc_s(size_t, &mxpos), mxn, mxind, &storage, ipme4.s, ipme4.len >> 2, ipme6.s, ipme6.len >> 4) ;
- genalloc_free(size_t, &mxpos) ;
}
diff --git a/src/qmail-smtpc/qmail-smtpc.h b/src/qmail-smtpc/qmail-smtpc.h
index 05431c8..29aa792 100644
--- a/src/qmail-smtpc/qmail-smtpc.h
+++ b/src/qmail-smtpc/qmail-smtpc.h
@@ -27,9 +27,7 @@ struct mxip_s
} ;
#define MXIP_ZERO { 0 }
-extern void dns_init (void) ;
-extern void dns_canon (char const *, char const *const *, unsigned int, size_t *, genalloc *, stralloc *) ;
-extern void dns_ip_of_mx (size_t const *, unsigned int, mxip *, stralloc *, char const *, unsigned int, char const *, unsigned int) ;
+extern void dns_stuff (char const *, char const *const *, unsigned int, size_t *, genalloc *, stralloc *, unsigned int, char const *, unsigned int, char const *, unsigned int, uint32_t) ;
/* smtproutes */
diff --git a/src/qmail-smtpc/qmailr.h b/src/qmail-smtpc/qmailr.h
index 803437b..08c4f41 100644
--- a/src/qmail-smtpc/qmailr.h
+++ b/src/qmail-smtpc/qmailr.h
@@ -30,6 +30,7 @@ extern void qmailr_diesys (char const *) gccattr_noreturn ;
extern int qmailr_memcmp4 (void const *, void const *) ;
extern int qmailr_memcmp16 (void const *, void const *) ;
+extern int qmailr_box_encode (char const *, size_t, stralloc *) ;
/* qmailr_tcpto */
@@ -53,6 +54,7 @@ struct qmailr_tls_s
size_t tapos ;
size_t certpos ;
size_t keypos ;
+ uint8_t strictness : 2 ;
uint8_t flagtls : 1 ;
uint8_t flagtadir : 1 ;
uint8_t flagclientcert : 1 ;
diff --git a/src/qmail-smtpc/qmailr_tls.c b/src/qmail-smtpc/qmailr_tls.c
index 50625e2..6e09a82 100644
--- a/src/qmail-smtpc/qmailr_tls.c
+++ b/src/qmail-smtpc/qmailr_tls.c
@@ -10,6 +10,7 @@ int qmailr_tls_init (qmailr_tls *qt, stralloc *sa)
static char const *tafile = SMTPD_STARTTLS_PROXY_QMAIL_HOME "/control/trustanchors" ;
static char const *certfile = SMTPD_STARTTLS_PROXY_QMAIL_HOME "/control/clientcert" ;
static char const *keyfile = SMTPD_STARTTLS_PROXY_QMAIL_HOME "/control/clientkey" ;
+ static char const *strictfile = SMTPD_STARTTLS_PROXY_QMAIL_HOME "/control/tlsstrictness" ;
qmailr_tls tmp = QMAILR_TLS_ZERO ;
size_t sabase = sa->len ;
@@ -17,6 +18,7 @@ int qmailr_tls_init (qmailr_tls *qt, stralloc *sa)
if (r == -1) return 0 ;
if (r)
{
+ unsigned int strictness = 0 ;
tmp.flagtls = 1 ;
if (sa->s[sa->len - 2] == '/')
{
@@ -31,6 +33,9 @@ int qmailr_tls_init (qmailr_tls *qt, stralloc *sa)
if (r == -1) goto err ;
if (r) tmp.flagclientcert = 1 ;
}
+ r = qmailr_control_readint(strictfile, &strictness, sa) ;
+ if (r == -1) goto err ;
+ tmp.strictness = strictness & 3 ;
}
*qt = tmp ;
diff --git a/src/qmail-smtpc/qmailr_utils.c b/src/qmail-smtpc/qmailr_utils.c
index 177a356..deeff46 100644
--- a/src/qmail-smtpc/qmailr_utils.c
+++ b/src/qmail-smtpc/qmailr_utils.c
@@ -2,6 +2,9 @@
#include <string.h>
+#include <skalibs/bitarray.h>
+#include <skalibs/stralloc.h>
+
#include "qmailr.h"
int qmailr_memcmp4 (void const *a, void const *b)
@@ -13,3 +16,45 @@ int qmailr_memcmp16 (void const *a, void const *b)
{
return memcmp(a, b, 16) ;
}
+
+static inline int needsquoting (char const *s, size_t len)
+{
+ static unsigned char const badchar[32] =
+ {
+ 0xff, 0xff, 0xff, 0xff,
+ 0x05, 0x13, 0x00, 0x5c,
+ 0x01, 0x00, 0x00, 0x38,
+ 0x00, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ } ;
+ if (!len) return 1 ;
+ if (s[0] == '.' || s[len - 1] == '.') return 1 ;
+ for (size_t i = 0 ; i < len ; i++)
+ {
+ if (bitarray_peek(badchar, (unsigned char)s[i])) return 1 ;
+ if (i + 2 < len && s[i] == '.' && s[i+1] == '.') return 1 ;
+ }
+ return 0 ;
+}
+
+int qmailr_box_encode (char const *s, size_t len, stralloc *storage)
+{
+ if (needsquoting(s, len))
+ {
+ size_t j = storage->len ;
+ if (!stralloc_readyplus(storage, 2 + (len << 1))) return 0 ;
+ storage->s[j++] = '"' ;
+ for (size_t i = 0 ; i < len ; i++)
+ {
+ if (strchr("\"\\\r\n", s[i])) storage->s[j++] = '\\' ;
+ storage->s[j++] = s[i] ;
+ }
+ storage->s[j++] = '"' ;
+ storage->len = j ;
+ }
+ else if (!stralloc_catb(storage, s, len)) return 0 ;
+ return 1 ;
+}