aboutsummaryrefslogtreecommitdiff
path: root/src/domain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/domain.c')
-rw-r--r--src/domain.c482
1 files changed, 403 insertions, 79 deletions
diff --git a/src/domain.c b/src/domain.c
index 027038e283db..501af2ad4238 100644
--- a/src/domain.c
+++ b/src/domain.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998-2004, 2006, 2010 Proofpoint, Inc. and its suppliers.
+ * Copyright (c) 1998-2004, 2006, 2010, 2020-2023 Proofpoint, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1986, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
@@ -13,9 +13,6 @@
#include <sendmail.h>
#include "map.h"
-#if USE_EAI
-#include <unicode/uidna.h>
-#endif
#if NAMED_BIND
SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (with name server)")
@@ -27,7 +24,7 @@ SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (without name s
#if NAMED_BIND
# include <arpa/inet.h>
-# include <sm_resolve.h>
+# include "sm_resolve.h"
# if DANE
# include <tls.h>
# ifndef SM_NEG_TTL
@@ -35,6 +32,10 @@ SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (without name s
# endif
# endif
+#if USE_EAI
+#include <unicode/uidna.h>
+#endif
+
# ifndef MXHOSTBUFSIZE
# define MXHOSTBUFSIZE (128 * MAXMXHOSTS)
@@ -53,10 +54,6 @@ static char MXHostBuf[MXHOSTBUFSIZE];
# define RES_DNSRCH_VARIABLE _res.dnsrch
# endif
-# ifndef NO_DATA
-# define NO_DATA NO_ADDRESS
-# endif
-
# ifndef HFIXEDSZ
# define HFIXEDSZ 12 /* sizeof(HEADER) */
# endif
@@ -74,6 +71,230 @@ static int fallbackmxrr __P((int, unsigned short *, char **));
# if DANE
+static void tlsa_rr_print __P((const unsigned char *, unsigned int));
+
+static void
+tlsa_rr_print(rr, len)
+ const unsigned char *rr;
+ unsigned int len;
+{
+ unsigned int i, l;
+
+ if (!tTd(8, 2))
+ return;
+
+ sm_dprintf("len=%u, %02x-%02x-%02x",
+ len, (int)rr[0], (int)rr[1], (int)rr[2]);
+ l = tTd(8, 8) ? len : 4;
+ for (i = 3; i < l; i++)
+ sm_dprintf(":%02X", (int)rr[i]);
+ sm_dprintf("\n");
+}
+
+/*
+** TLSA_RR_CMP -- Compare two TLSA RRs
+**
+** Parameters:
+** rr1 -- TLSA RR (entry to be added)
+** l1 -- length of rr1
+** rr2 -- TLSA RR
+** l2 -- length of rr2
+**
+** Returns:
+** 0: rr1 == rr2
+** 1: rr1 is unsupported
+*/
+
+static int tlsa_rr_cmp __P((unsigned char *, int, unsigned char *, int));
+
+static int
+tlsa_rr_cmp(rr1, l1, rr2, l2)
+ unsigned char *rr1;
+ int l1;
+ unsigned char *rr2;
+ int l2;
+{
+/* temporary #if while investigating the implications of the alternative */
+#if FULL_COMPARE
+ unsigned char r1, r2;
+ int cmp;
+#endif /* FULL_COMPARE */
+
+ SM_REQUIRE(NULL != rr1);
+ SM_REQUIRE(NULL != rr2);
+ SM_REQUIRE(l1 > 3);
+ SM_REQUIRE(l2 > 3);
+
+#if FULL_COMPARE
+ /*
+ ** certificate usage
+ ** 3: cert/fp must match
+ ** 2: cert/fp must be trust anchor
+ */
+
+ /* preference[]: lower value: higher preference */
+ r1 = rr1[0];
+ r2 = rr2[0];
+ if (r1 != r2)
+ {
+ int preference[] = { 3, 2, 1, 0 };
+
+ SM_ASSERT(r1 <= SM_ARRAY_SIZE(preference));
+ SM_ASSERT(r2 <= SM_ARRAY_SIZE(preference));
+ return preference[r1] - preference[r2];
+ }
+
+ /*
+ ** selector:
+ ** 0: full cert
+ ** 1: fp
+ */
+
+ r1 = rr1[1];
+ r2 = rr2[1];
+ if (r1 != r2)
+ {
+ int preference[] = { 1, 0 };
+
+ SM_ASSERT(r1 <= SM_ARRAY_SIZE(preference));
+ SM_ASSERT(r2 <= SM_ARRAY_SIZE(preference));
+ return preference[r1] - preference[r2];
+ }
+
+ /*
+ ** matching type:
+ ** 0 -- Exact match
+ ** 1 -- SHA-256 hash
+ ** 2 -- SHA-512 hash
+ */
+
+ r1 = rr1[2];
+ r2 = rr2[2];
+ if (r1 != r2)
+ {
+ int preference[] = { 2, 0, 1 };
+
+ SM_ASSERT(r1 <= SM_ARRAY_SIZE(preference));
+ SM_ASSERT(r2 <= SM_ARRAY_SIZE(preference));
+ return preference[r1] - preference[r2];
+ }
+
+ /* not the same length despite the same type? */
+ if (l1 != l2)
+ return 1;
+ cmp = memcmp(rr1, rr2, l1);
+ if (0 == cmp)
+ return 0;
+ return 1;
+#else /* FULL_COMPARE */
+ /* identical? */
+ if (l1 == l2 && 0 == memcmp(rr1, rr2, l1))
+ return 0;
+
+ /* new entry is unsupported? -> append */
+ if (TLSA_UNSUPP == dane_tlsa_chk(rr1, l1, "", false))
+ return 1;
+ /* current entry is unsupported? -> insert new one */
+ if (TLSA_UNSUPP == dane_tlsa_chk(rr2, l2, "", false))
+ return -1;
+
+ /* default: preserve order */
+ return 1;
+#endif /* FULL_COMPARE */
+}
+
+/*
+** TLSAINSERT -- Insert a TLSA RR
+**
+** Parameters:
+** dane_tlsa -- dane_tlsa entry
+** rr -- TLSA RR
+** pn -- (point to) number of entries
+**
+** Returns:
+** SM_SUCCESS: rr inserted
+** SM_NOTDONE: rr not inserted: exists
+** SM_FULL: rr not inserted: no space left
+*/
+
+static int tlsainsert __P((dane_tlsa_P, RESOURCE_RECORD_T *, int *));
+
+static int
+tlsainsert(dane_tlsa, rr, pn)
+ dane_tlsa_P dane_tlsa;
+ RESOURCE_RECORD_T *rr;
+ int *pn;
+{
+ int i, l1, ret;
+ unsigned char *r1;
+
+ SM_ASSERT(pn != NULL);
+ SM_ASSERT(*pn <= MAX_TLSA_RR);
+ r1 = rr->rr_u.rr_data;
+ l1 = rr->rr_size;
+
+ ret = SM_SUCCESS;
+ for (i = 0; i < *pn; i++)
+ {
+ int r, j;
+
+ r = tlsa_rr_cmp(r1, l1, dane_tlsa->dane_tlsa_rr[i],
+ dane_tlsa->dane_tlsa_len[i]);
+
+ if (0 == r)
+ {
+ if (tTd(8, 80))
+ sm_dprintf("func=tlsainsert, i=%d, n=%d, status=exists\n", i, *pn);
+ ret = SM_NOTDONE;
+ goto done;
+ }
+ if (r > 0)
+ continue;
+
+ if (*pn + 1 >= MAX_TLSA_RR)
+ {
+ j = MAX_TLSA_RR - 1;
+ SM_FREE(dane_tlsa->dane_tlsa_rr[j]);
+ dane_tlsa->dane_tlsa_len[j] = 0;
+ }
+ else
+ (*pn)++;
+
+ for (j = MAX_TLSA_RR - 2; j >= i; j--)
+ {
+ dane_tlsa->dane_tlsa_rr[j + 1] = dane_tlsa->dane_tlsa_rr[j];
+ dane_tlsa->dane_tlsa_len[j + 1] = dane_tlsa->dane_tlsa_len[j];
+ }
+ SM_ASSERT(i < MAX_TLSA_RR);
+ dane_tlsa->dane_tlsa_rr[i] = r1;
+ dane_tlsa->dane_tlsa_len[i] = l1;
+ if (tTd(8, 80))
+ sm_dprintf("func=tlsainsert, i=%d, n=%d, status=inserted\n", i, *pn);
+ goto added;
+ }
+
+ if (*pn + 1 <= MAX_TLSA_RR)
+ {
+ dane_tlsa->dane_tlsa_rr[*pn] = r1;
+ dane_tlsa->dane_tlsa_len[*pn] = l1;
+ (*pn)++;
+ if (tTd(8, 80))
+ sm_dprintf("func=tlsainsert, n=%d, status=appended\n", *pn);
+ }
+ else
+ {
+ if (tTd(8, 80))
+ sm_dprintf("func=tlsainsert, n=%d, status=full\n", *pn);
+ return SM_FULL;
+ }
+
+ added:
+ /* hack: instead of copying the data, just "take it over" */
+ rr->rr_u.rr_data = NULL;
+ done:
+ return ret;
+}
+
/*
** TLSAADD -- add TLSA records to dane_tlsa entry
**
@@ -82,24 +303,27 @@ static int fallbackmxrr __P((int, unsigned short *, char **));
** dr -- DNS reply
** dane_tlsa -- dane_tlsa entry
** dnsrc -- DNS lookup return code (h_errno)
-** n -- current number of TLSA records in dane_tlsa entry
+** nr -- current number of TLSA records in dane_tlsa entry
** pttl -- (pointer to) TTL (in/out)
** level -- recursion level (CNAMEs)
**
** Returns:
** new number of TLSA records
+**
+** NOTE: the array for TLSA RRs could be "full" which is not
+** handled well (yet).
*/
static int tlsaadd __P((const char *, DNS_REPLY_T *, dane_tlsa_P, int, int,
unsigned int *, int));
static int
-tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
+tlsaadd(name, dr, dane_tlsa, dnsrc, nr, pttl, level)
const char *name;
DNS_REPLY_T *dr;
dane_tlsa_P dane_tlsa;
int dnsrc;
- int n;
+ int nr;
unsigned int *pttl;
int level;
{
@@ -110,7 +334,7 @@ tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
if (dnsrc != 0)
{
if (tTd(8, 2))
- sm_dprintf("tlsaadd(%s), prev=%d, dnsrc=%d\n",
+ sm_dprintf("tlsaadd, name=%s, prev=%d, dnsrc=%d\n",
name, dane_tlsa->dane_tlsa_dnsrc, dnsrc);
/* check previous error and keep the "most important" one? */
@@ -122,61 +346,79 @@ tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
# endif
/* "else" in #if code above */
*pttl = SM_NEG_TTL;
- return n;
+ return nr;
}
if (dr == NULL)
- return n;
+ return nr;
if (dr->dns_r_h.ad != 1 && Dane == DANE_SECURE) /* not secure? */
- return n;
+ return nr;
ttl = *pttl;
/* first: try to find TLSA records */
- nprev = n;
- for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR;
- rr = rr->rr_next)
+ nprev = nr;
+ for (rr = dr->dns_r_head; rr != NULL; rr = rr->rr_next)
{
- int tlsa_chk;
+ int tlsa_chk, r;
if (rr->rr_type != T_TLSA)
{
if (rr->rr_type != T_CNAME && tTd(8, 8))
- sm_dprintf("tlsaadd(%s), type=%s\n", name,
+ sm_dprintf("tlsaadd: name=%s, type=%s\n", name,
dns_type_to_string(rr->rr_type));
continue;
}
tlsa_chk = dane_tlsa_chk(rr->rr_u.rr_data, rr->rr_size, name,
true);
+ if (TLSA_UNSUPP == tlsa_chk)
+ TLSA_SET_FL(dane_tlsa, TLSAFLUNS);
if (!TLSA_IS_VALID(tlsa_chk))
continue;
+ if (TLSA_IS_SUPPORTED(tlsa_chk))
+ TLSA_SET_FL(dane_tlsa, TLSAFLSUP);
/*
- ** To do: the RRs should be sorted (by "complexity") --
- ** when more than one type is supported.
+ ** Note: rr_u.rr_data might be NULL after tlsainsert()
+ ** for nice debug output: print the data into a string
+ ** and then use it after tlsainsert().
*/
- dane_tlsa->dane_tlsa_rr[n] = rr->rr_u.rr_data;
- dane_tlsa->dane_tlsa_len[n] = rr->rr_size;
if (tTd(8, 2))
{
- unsigned char *p;
-
- p = rr->rr_u.rr_data;
- sm_dprintf("tlsaadd(%s), n=%d, %d-%d-%d:%02x\n", name,
- n, (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
+ sm_dprintf("tlsaadd: name=%s, nr=%d, ", name, nr);
+ tlsa_rr_print(rr->rr_u.rr_data, rr->rr_size);
}
+ r = tlsainsert(dane_tlsa, rr, &nr);
+ if (SM_FULL == r)
+ TLSA_SET_FL(dane_tlsa, TLSAFL2MANY);
+ if (tTd(8, 2))
+ sm_dprintf("tlsainsert=%d, nr=%d\n", r, nr);
/* require some minimum TTL? */
if (ttl > rr->rr_ttl && rr->rr_ttl > 0)
ttl = rr->rr_ttl;
+ }
- /* hack: instead of copying the data, just "take it over" */
- rr->rr_u.rr_data = NULL;
- ++n;
+ if (tTd(8, 2))
+ {
+ unsigned int ui;
+
+ SM_ASSERT(nr <= MAX_TLSA_RR);
+ for (ui = 0; ui < (unsigned int)nr; ui++)
+ {
+ sm_dprintf("tlsaadd: name=%s, ui=%u, ", name, ui);
+ tlsa_rr_print(dane_tlsa->dane_tlsa_rr[ui],
+ dane_tlsa->dane_tlsa_len[ui]);
+ }
+ }
+
+ if (TLSA_IS_FL(dane_tlsa, TLSAFL2MANY))
+ {
+ if (tTd(8, 20))
+ sm_dprintf("tlsaadd: name=%s, rr=%p, nr=%d, toomany=%d\n", name, rr, nr, TLSA_IS_FL(dane_tlsa, TLSAFL2MANY));
}
/* second: check for CNAME records, but only if no TLSA RR was added */
- for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR && nprev == n;
- rr = rr->rr_next)
+ for (rr = dr->dns_r_head; rr != NULL && nprev == nr; rr = rr->rr_next)
{
DNS_REPLY_T *drc;
int err, herr;
@@ -186,30 +428,35 @@ tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
if (level > 1)
{
if (tTd(8, 2))
- sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d\n",
+ sm_dprintf("tlsaadd: name=%s, CNAME=%s, level=%d\n",
name, rr->rr_u.rr_txt, level);
continue;
}
drc = dns_lookup_int(rr->rr_u.rr_txt, C_IN, T_TLSA, 0, 0,
- (Dane == DANE_SECURE &&
- !TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX))
- ? SM_RES_DNSSEC : 0,
+ Dane == DANE_SECURE ? SM_RES_DNSSEC : 0,
RR_RAW, &err, &herr);
if (tTd(8, 2))
- sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d, dr=%p, ad=%d, err=%d, herr=%d\n",
+ sm_dprintf("tlsaadd: name=%s, CNAME=%s, level=%d, dr=%p, ad=%d, err=%d, herr=%d\n",
name, rr->rr_u.rr_txt, level,
(void *)drc, drc != NULL ? drc->dns_r_h.ad : -1,
err, herr);
- nprev = n = tlsaadd(name, drc, dane_tlsa, herr, n, pttl,
+ nprev = nr = tlsaadd(name, drc, dane_tlsa, herr, nr, pttl,
level + 1);
dns_free_data(drc);
drc = NULL;
}
+ if (TLSA_IS_FL(dane_tlsa, TLSAFLUNS) &&
+ !TLSA_IS_FL(dane_tlsa, TLSAFLSUP) && LogLevel > 9)
+ {
+ sm_syslog(LOG_NOTICE, NOQID,
+ "TLSA=%s, records=%d%s",
+ name, nr, ONLYUNSUPTLSARR);
+ }
*pttl = ttl;
- return n;
+ return nr;
}
/*
@@ -221,7 +468,7 @@ tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
** pste -- (pointer to) stab entry (output)
** flags -- TLSAFL*
** mxttl -- TTL of MX (or host)
-** port -- port
+** port -- port number used in TLSA queries (_PORT._tcp.)
**
** Returns:
** The number of TLSA records found.
@@ -248,7 +495,7 @@ gettlsa(host, name, pste, flags, mxttl, port)
time_t now;
unsigned int ttl;
int n_rrs, len, err, herr;
- bool isrname;
+ bool isrname, expired;
char nbuf[MAXDNAME];
char key[MAXDNAME];
@@ -258,9 +505,26 @@ gettlsa(host, name, pste, flags, mxttl, port)
if ('\0' == *host)
return 0;
+ expired = false;
isrname = NULL == name;
if (isrname)
name = host;
+
+ /*
+ ** If host->MX lookup was not secure then do not look up TLSA RRs.
+ ** Note: this is currently a hack: TLSAFLADMX is used as input flag,
+ ** it is (SHOULD!) NOT stored in dane_tlsa->dane_tlsa_flags
+ */
+
+ if (DANE_SECURE == Dane && 0 == (TLSAFLADMX & flags) &&
+ 0 != (TLSAFLNEW & flags))
+ {
+ if (tTd(8, 2))
+ sm_dprintf("gettlsa: host=%s, flags=%#lx, no ad but Dane=Secure\n",
+ host, flags);
+ return 0;
+ }
+
now = 0;
n_rrs = 0;
dr = NULL;
@@ -273,35 +537,37 @@ gettlsa(host, name, pste, flags, mxttl, port)
}
else
len = -1;
- if (0 == port || tTd(66, 10))
+ if (0 == port || tTd(66, 101))
port = 25;
- (void) sm_snprintf(key, sizeof(key), "_%u..%s", port, name);
+ (void) sm_snprintf(key, sizeof(key), "_%u.%s", port, name);
ste = stab(key, ST_TLSA_RR, ST_FIND);
if (tTd(8, 2))
- sm_dprintf("gettlsa(%s, %s, ste=%p, pste=%p, flags=%lX, port=%d)\n",
+ sm_dprintf("gettlsa: host=%s, %s, ste=%p, pste=%p, flags=%#lx, port=%d\n",
host, isrname ? "" : name, (void *)ste, (void *)pste,
flags, port);
if (ste != NULL)
- {
dane_tlsa = ste->s_tlsa;
- if ((TLSAFLADMX & flags) != 0)
- TLSA_CLR_FL(ste->s_tlsa, TLSAFLNOADMX);
- }
-
- /* Do not reload TLSA RRs if the MX RRs were not securely retrieved. */
- if (pste != NULL
- && dane_tlsa != NULL && TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX)
- && DANE_SECURE == Dane)
- goto end;
+#if 0
+// /* Do not reload TLSA RRs if the MX RRs were not securely retrieved. */
+// if (pste != NULL
+// && dane_tlsa != NULL && TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX)
+// && DANE_SECURE == Dane)
+// goto end;
+#endif
if (ste != NULL)
{
SM_ASSERT(dane_tlsa != NULL);
now = curtime();
+ if (tTd(8, 20))
+ sm_dprintf("gettlsa: host=%s, found-ste=%p, ste_flags=%#lx, expired=%d\n", host, ste, ste->s_tlsa->dane_tlsa_flags, dane_tlsa->dane_tlsa_exp <= now);
if (dane_tlsa->dane_tlsa_exp <= now
&& 0 == (TLSAFLNOEXP & flags))
+ {
dane_tlsa_clr(dane_tlsa);
+ expired = true;
+ }
else
{
n_rrs = dane_tlsa->dane_tlsa_n;
@@ -309,6 +575,10 @@ gettlsa(host, name, pste, flags, mxttl, port)
}
}
+ /* get entries if none exist yet? */
+ if ((0 == (TLSAFLNEW & flags)) && !expired)
+ goto end;
+
if (dane_tlsa == NULL)
{
dane_tlsa = (dane_tlsa_P) sm_malloc(sizeof(*dane_tlsa));
@@ -330,11 +600,38 @@ gettlsa(host, name, pste, flags, mxttl, port)
(void) sm_snprintf(nbuf, sizeof(nbuf), "_%u._tcp.%s", port, host);
dr = dns_lookup_int(nbuf, C_IN, T_TLSA, 0, 0,
- TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX) ? 0 : SM_RES_DNSSEC,
+ (TLSAFLADMX & flags) ? SM_RES_DNSSEC : 0,
RR_RAW, &err, &herr);
if (tTd(8, 2))
- sm_dprintf("gettlsa(%s), dr=%p, ad=%d, err=%d, herr=%d\n", host,
- (void *)dr, dr != NULL ? dr->dns_r_h.ad : -1, err, herr);
+ {
+#if 0
+/* disabled -- what to do with these two counters? log them "somewhere"? */
+// if (NULL != dr && tTd(8, 12))
+// {
+// RESOURCE_RECORD_T *rr;
+// unsigned int ntlsarrs, usable;
+//
+// ntlsarrs = usable = 0;
+// for (rr = dr->dns_r_head; rr != NULL; rr = rr->rr_next)
+// {
+// int tlsa_chk;
+//
+// if (rr->rr_type != T_TLSA)
+// continue;
+// ++ntlsarrs;
+// tlsa_chk = dane_tlsa_chk(rr->rr_u.rr_data,
+// rr->rr_size, name, false);
+// if (TLSA_IS_SUPPORTED(tlsa_chk))
+// ++usable;
+//
+// }
+// sm_dprintf("gettlsa: host=%s, ntlsarrs=%u, usable\%u\n", host, ntlsarrs, usable);
+// }
+#endif /* 0 */
+ sm_dprintf("gettlsa: host=%s, dr=%p, ad=%d, err=%d, herr=%d\n",
+ host, (void *)dr,
+ dr != NULL ? dr->dns_r_h.ad : -1, err, herr);
+ }
ttl = UINT_MAX;
n_rrs = tlsaadd(key, dr, dane_tlsa, herr, n_rrs, &ttl, 0);
@@ -342,7 +639,7 @@ gettlsa(host, name, pste, flags, mxttl, port)
if (n_rrs == 0 && !TLSA_RR_TEMPFAIL(dane_tlsa))
{
if (tTd(8, 2))
- sm_dprintf("gettlsa(%s), n_rrs=%d, herr=%d, status=NOT_ADDED\n",
+ sm_dprintf("gettlsa: host=%s, n_rrs=%d, herr=%d, status=NOT_ADDED\n",
host, n_rrs, dane_tlsa->dane_tlsa_dnsrc);
goto cleanup;
}
@@ -370,7 +667,7 @@ gettlsa(host, name, pste, flags, mxttl, port)
error:
if (tTd(8, 2))
- sm_dprintf("gettlsa(%s, %s), status=error\n", host, key);
+ sm_dprintf("gettlsa: host=%s, key=%s, status=error\n", host, key);
n_rrs = -1;
cleanup:
if (NULL == ste)
@@ -426,15 +723,18 @@ getfallbackmxrr(host)
if (NumFallbackMXHosts > 0 && renew > curtime())
return NumFallbackMXHosts;
- /* for DANE we need to invoke getmxrr() to get the TLSA RRs. */
-# if !DANE
- if (host[0] == '[')
+ /*
+ ** For DANE we need to invoke getmxrr() to get the TLSA RRs.
+ ** Hack: don't do that if its not a FQHN (e.g., [localhost])
+ ** This also triggers for IPv4 addresses, but not IPv6!
+ */
+
+ if (host[0] == '[' && (!Dane || strchr(host, '.') == NULL))
{
fbhosts[0] = host;
NumFallbackMXHosts = 1;
}
else
-# endif
{
/* free old data */
for (i = 0; i < NumFallbackMXHosts; i++)
@@ -448,10 +748,9 @@ getfallbackmxrr(host)
NumFallbackMXHosts = getmxrr(host, fbhosts, NULL,
# if DANE
- (DANE_SECURE == Dane) ? ISAD :
+ (DANE_SECURE == Dane) ? ISAD :
# endif
- 0,
- &rcode, &ttl, 0);
+ 0, &rcode, &ttl, 0, NULL);
renew = curtime() + ttl;
for (i = 0; i < NumFallbackMXHosts; i++)
fbhosts[i] = newstr(fbhosts[i]);
@@ -518,7 +817,7 @@ hn2alabel(hostname)
UIDNA *idna;
static char buf[MAXNAME_I]; /* XXX ??? */
- if (addr_is_ascii(hostname))
+ if (str_is_print(hostname))
return hostname;
idna = uidna_openUTS46(UIDNA_NONTRANSITIONAL_TO_ASCII, &error);
(void) uidna_nameToASCII_UTF8(idna, hostname, strlen(hostname),
@@ -538,13 +837,15 @@ hn2alabel(hostname)
** mxprefs -- a pointer to a return buffer of MX preferences.
** If NULL, don't try to populate.
** flags -- flags:
-** DROPLOCALHOSt -- If true, all MX records less preferred
+** DROPLOCALHOST -- If true, all MX records less preferred
** than the local host (as determined by $=w) will
** be discarded.
** TRYFALLBACK -- add also fallback MX host?
** ISAD -- host lookup was secure?
** rcode -- a pointer to an EX_ status code.
** pttl -- pointer to return TTL (can be NULL).
+** port -- port number used in TLSA queries (_PORT._tcp.)
+** pad -- (output parameter, pointer to) AD flag (can be NULL)
**
** Returns:
** The number of MX records found.
@@ -559,7 +860,7 @@ hn2alabel(hostname)
*/
int
-getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
+getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port, pad)
char *host;
char **mxhosts;
unsigned short *mxprefs;
@@ -567,6 +868,7 @@ getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
int *rcode;
int *pttl;
int port;
+ int *pad;
{
register unsigned char *eom, *cp;
register int i, j, n;
@@ -640,7 +942,7 @@ getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
# endif /* DANE */
# if USE_EAI
- if (!addr_is_ascii(host))
+ if (!str_is_print(host))
{
/* XXX memory leak? */
host = sm_rpool_strdup_x(CurEnv->e_rpool, hn2alabel(host));
@@ -727,6 +1029,8 @@ getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
ad = ad && hp->ad;
if (tTd(8, 2))
sm_dprintf("getmxrr(%s), hp=%p, ad=%d\n", host, (void*)hp, ad);
+ if (pad != NULL)
+ *pad = ad;
/* avoid problems after truncation in tcp packets */
if (n > sizeof(answer))
@@ -813,14 +1117,22 @@ getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
int nrr;
unsigned long flags;
- flags = ad ? TLSAFLADMX : TLSAFLNOADMX;
+ flags = TLSAFLNEW;
+ if (pad != NULL && *pad)
+ flags |= TLSAFLADMX;
+ if (tTd(8, 20))
+ sm_dprintf("getmxrr: 1: host=%s, mx=%s, flags=%#lx\n", host, bp, flags);
nrr = gettlsa(bp, NULL, NULL, flags, ttl, port);
/* Only check qname if no TLSA RRs were found */
if (0 == nrr && cname2mx && '\0' != qname[0] &&
strcmp(qname, bp))
+ {
+ if (tTd(8, 20))
+ sm_dprintf("getmxrr: 2: host=%s, qname=%s, flags=%#lx\n", host, qname, flags);
gettlsa(qname, bp, NULL, flags, ttl, port);
/* XXX is this the right ad flag? */
+ }
}
# endif
@@ -1009,7 +1321,7 @@ punt:
char *hn;
hn = MXHostBuf + 1;
- if (!addr_is_ascii(hn))
+ if (!str_is_print(hn))
{
const char *ahn;
@@ -1058,8 +1370,16 @@ punt:
else
cttl = SM_DEFAULT_TTL;
- flags = (ad && n == HOST_SECURE)
- ? TLSAFLADMX : TLSAFLNOADMX;
+ flags = TLSAFLNEW;
+ if (ad && HOST_SECURE == n)
+ {
+ flags |= TLSAFLADMX;
+ if (pad != NULL)
+ *pad = ad;
+ }
+ if (TTD(8, 20))
+ sm_dprintf("getmxrr: 3: host=%s, mx=%s, flags=%#lx, ad=%d\n",
+ host, mxhosts[0], flags, ad);
nrr = gettlsa(mxhosts[0], NULL, NULL, flags,
cttl, port);
@@ -1070,9 +1390,13 @@ punt:
if (0 == nrr && '\0' != qname[0] &&
strcmp(qname, mxhosts[0]))
+ {
gettlsa(qname, mxhosts[0], NULL, flags,
cttl, port);
+ if (tTd(8, 20))
+ sm_dprintf("getmxrr: 4: host=%s, qname=%s, flags=%#lx\n", host, qname, flags);
/* XXX is this the right ad flag? */
+ }
}
# endif
}
@@ -1081,7 +1405,7 @@ punt:
/* if we have a default lowest preference, include that */
if (fallbackMX != NULL && !seenlocal)
{
- /* TODO: DNSsec status of fallbacks */
+ /* TODO: DNSSEC status of fallbacks */
nmx = fallbackmxrr(nmx, prefs, mxhosts);
}
done:
@@ -1175,7 +1499,7 @@ bestmx_map_lookup(map, name, av, statp)
# endif
_res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
- nmx = getmxrr(name, mxhosts, NULL, 0, statp, NULL, -1);
+ nmx = getmxrr(name, mxhosts, NULL, 0, statp, NULL, -1, NULL);
_res.options = saveopts;
if (nmx <= 0)
return NULL;