2 * Copyright (c) 1998-2004, 2006, 2010 Proofpoint, Inc. and its suppliers.
4 * Copyright (c) 1986, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
17 #include <unicode/uidna.h>
21 SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (with name server)")
23 SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (without name server)")
28 # include <arpa/inet.h>
29 # include <sm_resolve.h>
33 # define SM_NEG_TTL 60 /* "negative" TTL */
38 # ifndef MXHOSTBUFSIZE
39 # define MXHOSTBUFSIZE (128 * MAXMXHOSTS)
42 static char MXHostBuf[MXHOSTBUFSIZE];
43 # if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2)
44 ERROR: _MXHOSTBUFSIZE is out of range
48 # define MAXDNSRCH 6 /* number of possible domains to search */
51 # ifndef RES_DNSRCH_VARIABLE
52 # define RES_DNSRCH_VARIABLE _res.dnsrch
56 # define NO_DATA NO_ADDRESS
60 # define HFIXEDSZ 12 /* sizeof(HEADER) */
63 # define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */
65 # if defined(__RES) && (__RES >= 19940415)
66 # define RES_UNC_T char *
68 # define RES_UNC_T unsigned char *
71 static int mxrand __P((char *));
72 static int fallbackmxrr __P((int, unsigned short *, char **));
77 ** TLSAADD -- add TLSA records to dane_tlsa entry
80 ** name -- key for stab entry (for debugging output)
82 ** dane_tlsa -- dane_tlsa entry
83 ** dnsrc -- DNS lookup return code (h_errno)
84 ** n -- current number of TLSA records in dane_tlsa entry
85 ** pttl -- (pointer to) TTL (in/out)
86 ** level -- recursion level (CNAMEs)
89 ** new number of TLSA records
92 static int tlsaadd __P((const char *, DNS_REPLY_T *, dane_tlsa_P, int, int,
93 unsigned int *, int));
96 tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
99 dane_tlsa_P dane_tlsa;
105 RESOURCE_RECORD_T *rr;
112 sm_dprintf("tlsaadd(%s), prev=%d, dnsrc=%d\n",
113 name, dane_tlsa->dane_tlsa_dnsrc, dnsrc);
115 /* check previous error and keep the "most important" one? */
116 dane_tlsa->dane_tlsa_dnsrc = dnsrc;
119 *pttl = tTdlevel(8)-110; /* how to make this an option? */
129 if (dr->dns_r_h.ad != 1 && Dane == DANE_SECURE) /* not secure? */
133 /* first: try to find TLSA records */
135 for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR;
140 if (rr->rr_type != T_TLSA)
142 if (rr->rr_type != T_CNAME && tTd(8, 8))
143 sm_dprintf("tlsaadd(%s), type=%s\n", name,
144 dns_type_to_string(rr->rr_type));
147 tlsa_chk = dane_tlsa_chk(rr->rr_u.rr_data, rr->rr_size, name,
149 if (!TLSA_IS_VALID(tlsa_chk))
153 ** To do: the RRs should be sorted (by "complexity") --
154 ** when more than one type is supported.
157 dane_tlsa->dane_tlsa_rr[n] = rr->rr_u.rr_data;
158 dane_tlsa->dane_tlsa_len[n] = rr->rr_size;
163 p = rr->rr_u.rr_data;
164 sm_dprintf("tlsaadd(%s), n=%d, %d-%d-%d:%02x\n", name,
165 n, (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
168 /* require some minimum TTL? */
169 if (ttl > rr->rr_ttl && rr->rr_ttl > 0)
172 /* hack: instead of copying the data, just "take it over" */
173 rr->rr_u.rr_data = NULL;
177 /* second: check for CNAME records, but only if no TLSA RR was added */
178 for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR && nprev == n;
184 if (rr->rr_type != T_CNAME)
189 sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d\n",
190 name, rr->rr_u.rr_txt, level);
194 drc = dns_lookup_int(rr->rr_u.rr_txt, C_IN, T_TLSA, 0, 0,
195 (Dane == DANE_SECURE &&
196 !TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX))
198 RR_RAW, &err, &herr);
201 sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d, dr=%p, ad=%d, err=%d, herr=%d\n",
202 name, rr->rr_u.rr_txt, level,
203 (void *)drc, drc != NULL ? drc->dns_r_h.ad : -1,
205 nprev = n = tlsaadd(name, drc, dane_tlsa, herr, n, pttl,
216 ** GETTLSA -- get TLSA records for named host using DNS
220 ** name -- name for stab entry key (if NULL: host)
221 ** pste -- (pointer to) stab entry (output)
223 ** mxttl -- TTL of MX (or host)
227 ** The number of TLSA records found.
228 ** <0 if there is an internal failure.
231 ** Enters TLSA RRs into stab().
232 ** If the DNS lookup fails temporarily, an "empty" entry is
233 ** created with that DNS error code.
237 gettlsa(host, name, pste, flags, mxttl, port)
246 dane_tlsa_P dane_tlsa;
250 int n_rrs, len, err, herr;
255 SM_REQUIRE(host != NULL);
261 isrname = NULL == name;
269 if (len > 1 && name[len - 1] == '.')
276 if (0 == port || tTd(66, 10))
278 (void) sm_snprintf(key, sizeof(key), "_%u..%s", port, name);
279 ste = stab(key, ST_TLSA_RR, ST_FIND);
281 sm_dprintf("gettlsa(%s, %s, ste=%p, pste=%p, flags=%lX, port=%d)\n",
282 host, isrname ? "" : name, (void *)ste, (void *)pste,
287 dane_tlsa = ste->s_tlsa;
288 if ((TLSAFLADMX & flags) != 0)
289 TLSA_CLR_FL(ste->s_tlsa, TLSAFLNOADMX);
292 /* Do not reload TLSA RRs if the MX RRs were not securely retrieved. */
294 && dane_tlsa != NULL && TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX)
295 && DANE_SECURE == Dane)
300 SM_ASSERT(dane_tlsa != NULL);
302 if (dane_tlsa->dane_tlsa_exp <= now
303 && 0 == (TLSAFLNOEXP & flags))
304 dane_tlsa_clr(dane_tlsa);
307 n_rrs = dane_tlsa->dane_tlsa_n;
312 if (dane_tlsa == NULL)
314 dane_tlsa = (dane_tlsa_P) sm_malloc(sizeof(*dane_tlsa));
315 if (dane_tlsa == NULL)
320 memset(dane_tlsa, '\0', sizeof(*dane_tlsa));
323 /* There are flags to store -- just set those, do nothing else. */
324 if (TLSA_STORE_FL(flags))
326 dane_tlsa->dane_tlsa_flags = flags;
327 ttl = mxttl > 0 ? mxttl: SM_DEFAULT_TTL;
331 (void) sm_snprintf(nbuf, sizeof(nbuf), "_%u._tcp.%s", port, host);
332 dr = dns_lookup_int(nbuf, C_IN, T_TLSA, 0, 0,
333 TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX) ? 0 : SM_RES_DNSSEC,
334 RR_RAW, &err, &herr);
336 sm_dprintf("gettlsa(%s), dr=%p, ad=%d, err=%d, herr=%d\n", host,
337 (void *)dr, dr != NULL ? dr->dns_r_h.ad : -1, err, herr);
339 n_rrs = tlsaadd(key, dr, dane_tlsa, herr, n_rrs, &ttl, 0);
341 /* no valid entries found? */
342 if (n_rrs == 0 && !TLSA_RR_TEMPFAIL(dane_tlsa))
345 sm_dprintf("gettlsa(%s), n_rrs=%d, herr=%d, status=NOT_ADDED\n",
346 host, n_rrs, dane_tlsa->dane_tlsa_dnsrc);
351 dane_tlsa->dane_tlsa_n = n_rrs;
354 SM_FREE(dane_tlsa->dane_tlsa_sni);
355 dane_tlsa->dane_tlsa_sni = sm_strdup(host);
359 ste = stab(key, ST_TLSA_RR, ST_ENTER);
363 ste->s_tlsa = dane_tlsa;
366 dane_tlsa->dane_tlsa_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL);
373 sm_dprintf("gettlsa(%s, %s), status=error\n", host, key);
377 dane_tlsa_free(dane_tlsa);
382 if (pste != NULL && ste != NULL)
391 ** GETFALLBACKMXRR -- get MX resource records for fallback MX host.
393 ** We have to initialize this once before doing anything else.
394 ** Moreover, we have to repeat this from time to time to avoid
395 ** stale data, e.g., in persistent queue runners.
396 ** This should be done in a parent process so the child
397 ** processes have the right data.
400 ** host -- the name of the fallback MX host.
403 ** number of MX records.
406 ** Populates NumFallbackMXHosts and fbhosts.
407 ** Sets renewal time (based on TTL).
410 int NumFallbackMXHosts = 0; /* Number of fallback MX hosts (after MX expansion) */
411 static char *fbhosts[MAXMXHOSTS + 1];
414 getfallbackmxrr(host)
419 static time_t renew = 0;
422 /* This is currently done before this function is called. */
423 if (host == NULL || *host == '\0')
426 if (NumFallbackMXHosts > 0 && renew > curtime())
427 return NumFallbackMXHosts;
429 /* for DANE we need to invoke getmxrr() to get the TLSA RRs. */
434 NumFallbackMXHosts = 1;
440 for (i = 0; i < NumFallbackMXHosts; i++)
445 ** Note: passing 0 as port is not correct but we cannot
446 ** determine the port number as there is no mailer.
449 NumFallbackMXHosts = getmxrr(host, fbhosts, NULL,
451 (DANE_SECURE == Dane) ? ISAD :
455 renew = curtime() + ttl;
456 for (i = 0; i < NumFallbackMXHosts; i++)
457 fbhosts[i] = newstr(fbhosts[i]);
459 if (NumFallbackMXHosts == NULLMX)
460 NumFallbackMXHosts = 0;
461 return NumFallbackMXHosts;
465 ** FALLBACKMXRR -- add MX resource records for fallback MX host to list.
468 ** nmx -- current number of MX records.
469 ** prefs -- array of preferences.
470 ** mxhosts -- array of MX hosts (maximum size: MAXMXHOSTS)
473 ** new number of MX records.
476 ** If FallbackMX was set, it appends the MX records for
477 ** that host to mxhosts (and modifies prefs accordingly).
481 fallbackmxrr(nmx, prefs, mxhosts)
483 unsigned short *prefs;
488 for (i = 0; i < NumFallbackMXHosts && nmx < MAXMXHOSTS; i++)
491 prefs[nmx] = prefs[nmx - 1] + 1;
494 mxhosts[nmx++] = fbhosts[i];
500 ** GETMXRR -- get MX resource records for a domain
503 ** host -- the name of the host to MX.
504 ** mxhosts -- a pointer to a return buffer of MX records.
505 ** mxprefs -- a pointer to a return buffer of MX preferences.
506 ** If NULL, don't try to populate.
508 ** DROPLOCALHOSt -- If true, all MX records less preferred
509 ** than the local host (as determined by $=w) will
511 ** TRYFALLBACK -- add also fallback MX host?
512 ** ISAD -- host lookup was secure?
513 ** rcode -- a pointer to an EX_ status code.
514 ** pttl -- pointer to return TTL (can be NULL).
517 ** The number of MX records found.
518 ** -1 if there is an internal failure.
519 ** If no MX records are found, mxhosts[0] is set to host
520 ** and 1 is returned.
523 ** The entries made for mxhosts point to a static array
524 ** MXHostBuf[MXHOSTBUFSIZE], so the data needs to be copied,
525 ** if it must be preserved across calls to this function.
529 getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
532 unsigned short *mxprefs;
538 register unsigned char *eom, *cp;
539 register int i, j, n;
544 int ancount, qdcount, buflen;
545 bool seenlocal = false;
546 unsigned short pref, type;
547 unsigned short localpref = 256;
548 char *fallbackMX = FallbackMX;
549 bool trycanon = false;
550 unsigned short *prefs;
551 int (*resfunc) __P((const char *, int, int, u_char *, int));
552 unsigned short prefer[MAXMXHOSTS];
553 int weight[MAXMXHOSTS];
556 bool seennullmx = false;
557 extern int res_query(), res_search();
561 unsigned long old_options = 0;
565 sm_dprintf("getmxrr(%s, droplocalhost=%d, flags=%X, port=%d)\n",
566 host, (flags & DROPLOCALHOST) != 0, flags, port);
567 ad = (flags & ISAD) != 0;
570 *pttl = SM_DEFAULT_TTL;
576 old_options = _res.options;
578 _res.options |= SM_RES_DNSSEC;
581 if ((fallbackMX != NULL && (flags & DROPLOCALHOST) != 0 &&
582 wordinclass(fallbackMX, 'w')) || (flags & TRYFALLBACK) == 0)
584 /* don't use fallback for this pass */
593 /* efficiency hack -- numeric or non-MX lookups */
599 ** NOTE: This only works if nocanonify is used,
600 ** otherwise the name is already rewritten.
603 /* always or only when "needed"? */
604 if (DANE_ALWAYS == Dane || (ad && DANE_SECURE == Dane))
605 (void) sm_strlcpy(qname, host, sizeof(qname));
609 if (!addr_is_ascii(host))
612 UErrorCode error = U_ZERO_ERROR;
613 UIDNAInfo info = UIDNA_INFO_INITIALIZER;
616 idna = uidna_openUTS46(UIDNA_NONTRANSITIONAL_TO_ASCII, &error);
617 (void) uidna_nameToASCII_UTF8(idna, host, strlen(host),
618 buf, sizeof(buf) - 1,
621 host = sm_rpool_strdup_x(CurEnv->e_rpool, buf);
623 # endif /* _FFR_EAI */
626 ** If we don't have MX records in our host switch, don't
627 ** try for MX records. Note that this really isn't "right",
628 ** since we might be set up to try NIS first and then DNS;
629 ** if the host is found in NIS we really shouldn't be doing
630 ** MX lookups. However, that should be a degenerate case.
635 if (HasWildcardMX && ConfigLevel >= 6)
638 resfunc = res_search;
641 resfunc = tstdns_search;
645 hp = (HEADER *)&answer;
646 n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer,
652 sm_dprintf("getmxrr: res_search(%s) failed (errno=%d (%s), h_errno=%d (%s))\n",
653 host, errno, strerror(errno),
654 h_errno, herrno2txt(h_errno));
656 sm_dprintf("getmxrr: res_search(%s) failed, h_errno=%d\n",
666 /* no MX data on this host */
670 # if BROKEN_RES_SEARCH
671 case 0: /* Ultrix resolver returns failure w/ h_errno=0 */
673 /* host doesn't exist in DNS; might be in /etc/hosts */
680 /* couldn't connect to the name server */
681 if (fallbackMX != NULL)
683 /* name server is hosed -- push to fallback */
684 nmx = fallbackmxrr(nmx, prefs, mxhosts);
687 /* it might come up later; better queue it up */
688 *rcode = EX_TEMPFAIL;
692 syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)",
698 /* irreconcilable differences */
704 sm_dprintf("getmxrr(%s), hp=%p, ad=%d\n", host, (void*)hp, ad);
706 /* avoid problems after truncation in tcp packets */
707 if (n > sizeof(answer))
710 /* find first satisfactory answer */
711 cp = (unsigned char *)&answer + HFIXEDSZ;
712 eom = (unsigned char *)&answer + n;
714 for (qdcount = ntohs((unsigned short) hp->qdcount);
718 if ((n = dn_skipname(cp, eom)) < 0)
722 /* NOTE: see definition of MXHostBuf! */
723 buflen = sizeof(MXHostBuf) - 1;
724 SM_ASSERT(buflen > 0);
726 ancount = ntohs((unsigned short) hp->ancount);
728 /* See RFC 1035 for layout of RRs. */
729 /* XXX leave room for FallbackMX ? */
730 while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
732 if ((n = dn_expand((unsigned char *)&answer, eom, cp,
733 (RES_UNC_T) bp, buflen)) < 0)
737 cp += INT16SZ; /* skip over class */
739 GETSHORT(n, cp); /* rdlength */
746 if ((tTd(8, 8) || _res.options & RES_DEBUG)
751 sm_dprintf("unexpected answer type %s, size %d\n",
752 dns_type_to_string(type), n);
757 if ((n = dn_expand((unsigned char *)&answer, eom, cp,
758 (RES_UNC_T) bp, buflen)) < 0)
763 /* Support for RFC7505 "MX 0 ." */
764 if (pref == 0 && *bp == '\0')
767 if (wordinclass(bp, 'w'))
770 sm_dprintf("found localhost (%s) in MX list, pref=%d\n",
772 if ((flags & DROPLOCALHOST) != 0)
774 if (!seenlocal || pref < localpref)
782 weight[nmx] = mxrand(bp);
786 if (CHK_DANE(Dane) && port >= 0)
791 flags = ad ? TLSAFLADMX : TLSAFLNOADMX;
792 nrr = gettlsa(bp, NULL, NULL, flags, ttl, port);
794 /* Only check qname if no TLSA RRs were found */
795 if (0 == nrr && cname2mx && '\0' != qname[0] &&
797 gettlsa(qname, bp, NULL, flags, ttl, port);
798 /* XXX is this the right ad flag? */
803 ** Note: n can be 0 for something like:
809 if (0 == n || bp[-1] != '.')
817 /* don't want to wrap buflen */
823 /* Support for RFC7505 "MX 0 ." */
824 if (seennullmx && nmx == 1)
827 sm_dprintf("getmxrr: Null MX record found, domain doesn't accept mail (RFC7505)\n");
828 *rcode = EX_UNAVAILABLE;
832 /* return only one TTL entry, that should be sufficient */
833 if (ttl > 0 && pttl != NULL)
836 /* sort the records */
837 for (i = 0; i < nmx; i++)
839 for (j = i + 1; j < nmx; j++)
841 if (prefs[i] > prefs[j] ||
842 (prefs[i] == prefs[j] && weight[i] > weight[j]))
845 register char *temp1;
851 mxhosts[i] = mxhosts[j];
854 weight[i] = weight[j];
858 if (seenlocal && prefs[i] >= localpref)
860 /* truncate higher preference part of list */
865 /* delete duplicates from list (yes, some bozos have duplicates) */
866 for (i = 0; i < nmx - 1; )
868 if (sm_strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0)
872 /* compress out duplicate */
873 for (j = i + 1; j < nmx; j++)
875 mxhosts[j] = mxhosts[j + 1];
876 prefs[j] = prefs[j + 1];
887 struct hostent *h = NULL;
890 ** If we have deleted all MX entries, this is
891 ** an error -- we should NEVER send to a host that
892 ** has an MX, and this should have been caught
893 ** earlier in the config file.
895 ** Some sites prefer to go ahead and try the
896 ** A record anyway; that case is handled by
897 ** setting TryNullMXList. I believe this is a
898 ** bad idea, but it's up to you....
905 h = sm_gethostbyname(host, AF_INET);
908 if (errno == ETIMEDOUT ||
909 h_errno == TRY_AGAIN ||
910 (errno == ECONNREFUSED &&
913 *rcode = EX_TEMPFAIL;
919 h = sm_gethostbyname(host, AF_INET6);
921 (errno == ETIMEDOUT ||
922 h_errno == TRY_AGAIN ||
923 (errno == ECONNREFUSED &&
926 *rcode = EX_TEMPFAIL;
929 # endif /* NETINET6 */
936 syserr("MX list for %s points back to %s",
945 if (strlen(host) >= sizeof(MXHostBuf))
948 syserr("Host name %s too long",
949 shortenstring(host, MAXSHORTSTR));
952 (void) sm_strlcpy(MXHostBuf, host, sizeof(MXHostBuf));
953 mxhosts[0] = MXHostBuf;
959 struct sockaddr_in6 tmp6;
962 /* this may be an MX suppression-style address */
963 p = strchr(MXHostBuf, ']');
968 if (inet_addr(&MXHostBuf[1]) != INADDR_NONE)
974 else if (anynet_pton(AF_INET6, &MXHostBuf[1],
975 &tmp6.sin6_addr) == 1)
980 # endif /* NETINET6 */
989 (n = getcanonname(mxhosts[0], sizeof(MXHostBuf) - 2, false,
990 pttl)) != HOST_NOTFOUND)
992 /* XXX MXHostBuf == "" ? is that possible? */
993 bp = &MXHostBuf[strlen(MXHostBuf)];
1002 sm_dprintf("getmxrr=%s, getcanonname=%d\n",
1004 if (CHK_DANE(Dane) && port >= 0)
1007 unsigned long flags;
1015 cttl = SM_DEFAULT_TTL;
1017 flags = (ad && n == HOST_SECURE)
1018 ? TLSAFLADMX : TLSAFLNOADMX;
1019 nrr = gettlsa(mxhosts[0], NULL, NULL, flags,
1023 ** Only check qname if no TLSA RRs were found
1024 ** XXX: what about (temp) DNS errors?
1027 if (0 == nrr && '\0' != qname[0] &&
1028 strcmp(qname, mxhosts[0]))
1029 gettlsa(qname, mxhosts[0], NULL, flags,
1031 /* XXX is this the right ad flag? */
1037 /* if we have a default lowest preference, include that */
1038 if (fallbackMX != NULL && !seenlocal)
1040 /* TODO: DNSsec status of fallbacks */
1041 nmx = fallbackmxrr(nmx, prefs, mxhosts);
1045 _res.options = old_options;
1051 _res.options = old_options;
1057 ** MXRAND -- create a randomizer for equal MX preferences
1059 ** If two MX hosts have equal preferences we want to randomize
1060 ** the selection. But in order for signatures to be the same,
1061 ** we need to randomize the same way each time. This function
1062 ** computes a pseudo-random hash function from the host name.
1065 ** host -- the name of the host.
1068 ** A random but repeatable value based on the host name.
1073 register char *host;
1076 static unsigned int seed;
1080 seed = (int) curtime() & 0xffff;
1086 sm_dprintf("mxrand(%s)", host);
1089 while (*host != '\0')
1093 if (isascii(c) && isupper(c))
1095 hfunc = ((hfunc << 1) ^ c) % 2003;
1102 sm_dprintf(" = %d\n", hfunc);
1106 ** BESTMX -- find the best MX for a name
1108 ** This is really a hack, but I don't see any obvious way
1109 ** to generalize it at the moment.
1114 bestmx_map_lookup(map, name, av, statp)
1121 int saveopts = _res.options;
1125 char *mxhosts[MAXMXHOSTS + 1];
1126 # if _FFR_BESTMX_BETTER_TRUNCATION
1130 char buf[PSBUFSIZE / 2];
1133 _res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
1134 nmx = getmxrr(name, mxhosts, NULL, 0, statp, NULL, -1);
1135 _res.options = saveopts;
1138 if (bitset(MF_MATCHONLY, map->map_mflags))
1139 return map_rewrite(map, name, strlen(name), NULL);
1140 if ((map->map_coldelim == '\0') || (nmx == 1))
1141 return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
1144 ** We were given a -z flag (return all MXs) and there are multiple
1145 ** ones. We need to build them all into a list.
1148 # if _FFR_BESTMX_BETTER_TRUNCATION
1149 for (i = 0; i < nmx; i++)
1151 if (strchr(mxhosts[i], map->map_coldelim) != NULL)
1153 syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
1154 mxhosts[i], map->map_coldelim);
1157 len += strlen(mxhosts[i]) + 1;
1160 len -= strlen(mxhosts[i]) + 1;
1164 buf = (char *) sm_malloc(len);
1167 *statp = EX_UNAVAILABLE;
1171 for (i = 0; i < nmx; i++)
1175 end = sm_strlcat(buf, mxhosts[i], len);
1176 if (i != nmx && end + 1 < len)
1178 buf[end] = map->map_coldelim;
1179 buf[end + 1] = '\0';
1183 /* Cleanly truncate for rulesets */
1184 truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim);
1185 # else /* _FFR_BESTMX_BETTER_TRUNCATION */
1187 for (i = 0; i < nmx; i++)
1191 if (strchr(mxhosts[i], map->map_coldelim) != NULL)
1193 syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
1194 mxhosts[i], map->map_coldelim);
1197 slen = strlen(mxhosts[i]);
1198 if (len + slen + 2 > sizeof(buf))
1202 *p++ = map->map_coldelim;
1205 (void) sm_strlcpy(p, mxhosts[i], sizeof(buf) - len);
1209 # endif /* _FFR_BESTMX_BETTER_TRUNCATION */
1211 result = map_rewrite(map, buf, len, av);
1212 # if _FFR_BESTMX_BETTER_TRUNCATION
1218 ** DNS_GETCANONNAME -- get the canonical name for named host using DNS
1220 ** This algorithm tries to be smart about wildcard MX records.
1221 ** This is hard to do because DNS doesn't tell is if we matched
1222 ** against a wildcard or a specific MX.
1224 ** We always prefer A & CNAME records, since these are presumed
1227 ** If we match an MX in one pass and lose it in the next, we use
1228 ** the old one. For example, consider an MX matching *.FOO.BAR.COM.
1229 ** A hostname bletch.foo.bar.com will match against this MX, but
1230 ** will stop matching when we try bletch.bar.com -- so we know
1231 ** that bletch.foo.bar.com must have been right. This fails if
1232 ** there was also an MX record matching *.BAR.COM, but there are
1233 ** some things that just can't be fixed.
1236 ** host -- a buffer containing the name of the host.
1237 ** This is a value-result parameter.
1238 ** hbsize -- the size of the host buffer.
1239 ** trymx -- if set, try MX records as well as A and CNAME.
1240 ** statp -- pointer to place to store status.
1241 ** pttl -- pointer to return TTL (can be NULL).
1244 ** >0 -- if the host was found.
1249 dns_getcanonname(host, hbsize, trymx, statp, pttl)
1256 register unsigned char *eom, *ap;
1261 int ancount, qdcount, ret, type, qtype, initial, loopcnt, ttl, sli;
1265 bool amatch, gotmx, ad;
1266 char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)];
1268 # define ADDSL 1 /* NameSearchList may add another entry to searchlist! */
1272 char *searchlist[MAXDNSRCH + 2 + ADDSL];
1273 # define SLSIZE SM_ARRAY_SIZE(searchlist)
1274 int (*resqdomain) __P((const char *, const char *, int, int, unsigned char *, int));
1276 unsigned long old_options = 0;
1283 sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
1285 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
1287 *statp = EX_UNAVAILABLE;
1288 return HOST_NOTFOUND;
1292 old_options = _res.options;
1293 if (DANE_SECURE == Dane)
1294 _res.options |= SM_RES_DNSSEC;
1298 resqdomain = res_querydomain;
1301 resqdomain = tstdns_querydomain;
1305 ** Initialize domain search list. If there is at least one
1306 ** dot in the name, search the unmodified name first so we
1307 ** find "vse.CS" in Czechoslovakia instead of in the local
1308 ** domain (e.g., vse.CS.Berkeley.EDU). Note that there is no
1309 ** longer a country named Czechoslovakia but this type of problem
1310 ** is still present.
1312 ** Older versions of the resolver could create this
1313 ** list by tearing apart the host name.
1318 /* Check for dots in the name */
1319 for (cp = host, n = 0; *cp != '\0'; cp++)
1324 ** Build the search list.
1325 ** If there is at least one dot in name, start with a null
1326 ** domain to search the unmodified name first.
1327 ** If name does not end with a dot and search up local domain
1328 ** tree desired, append each local domain component to the
1329 ** search list; if name contains no dots and default domain
1330 ** name is desired, append default domain name to search list;
1331 ** else if name ends in a dot, remove that dot.
1336 searchlist[sli++] = "";
1338 if (NameSearchList != NULL)
1340 SM_ASSERT(sli < SLSIZE);
1341 searchlist[sli++] = NameSearchList;
1344 if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options))
1346 /* make sure there are less than MAXDNSRCH domains */
1347 for (domain = RES_DNSRCH_VARIABLE, ret = 0;
1348 *domain != NULL && ret < MAXDNSRCH && sli < SLSIZE;
1350 searchlist[sli++] = *domain++;
1352 else if (n == 0 && bitset(RES_DEFNAMES, _res.options))
1354 SM_ASSERT(sli < SLSIZE);
1355 searchlist[sli++] = _res.defdname;
1357 else if (*cp == '.')
1361 SM_ASSERT(sli < SLSIZE);
1362 searchlist[sli] = NULL;
1365 ** Now loop through the search list, appending each domain in turn
1366 ** name and searching for a match.
1372 if (InetMode == AF_INET6)
1377 for (sli = 0; sli < SLSIZE; )
1379 dp = searchlist[sli];
1382 if (qtype == initial)
1385 sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n",
1388 qtype == T_AAAA ? "AAAA" :
1390 qtype == T_A ? "A" :
1391 qtype == T_MX ? "MX" :
1394 hp = (HEADER *) &answer;
1395 ret = (*resqdomain)(host, dp, C_IN, qtype,
1396 answer.qb2, sizeof(answer.qb2));
1399 int save_errno = errno;
1402 sm_dprintf("\tNO: errno=%d, h_errno=%d\n",
1403 save_errno, h_errno);
1405 if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN)
1408 ** the name server seems to be down or broken.
1411 SM_SET_H_ERRNO(TRY_AGAIN);
1414 if (*statp == EX_OK)
1415 *statp = EX_TEMPFAIL;
1418 *statp = EX_TEMPFAIL;
1420 if (WorkAroundBrokenAAAA)
1423 ** Only return if not TRY_AGAIN as an
1424 ** attempt with a different qtype may
1425 ** succeed (res_querydomain() calls
1426 ** res_query() calls res_send() which
1427 ** sets errno to ETIMEDOUT if the
1428 ** nameservers could be contacted but
1429 ** didn't give an answer).
1432 if (save_errno != ETIMEDOUT)
1440 if (h_errno != HOST_NOT_FOUND)
1442 /* might have another type of interest */
1444 if (qtype == T_AAAA)
1450 # endif /* NETINET6 */
1451 if (qtype == T_A && !gotmx &&
1452 (trymx || *dp == '\0'))
1459 /* definite no -- try the next domain */
1465 sm_dprintf("\tYES\n");
1467 /* avoid problems after truncation in tcp packets */
1468 if (ret > sizeof(answer))
1469 ret = sizeof(answer);
1470 SM_ASSERT(ret >= 0);
1473 ** Appear to have a match. Confirm it by searching for A or
1474 ** CNAME records. If we don't have a local domain
1475 ** wild card MX record, we will accept MX as well.
1478 ap = (unsigned char *) &answer + HFIXEDSZ;
1479 eom = (unsigned char *) &answer + ret;
1484 /* skip question part of response -- we know what we asked */
1485 for (qdcount = ntohs((unsigned short) hp->qdcount);
1487 ap += ret + QFIXEDSZ)
1489 if ((ret = dn_skipname(ap, eom)) < 0)
1492 sm_dprintf("qdcount failure (%d)\n",
1493 ntohs((unsigned short) hp->qdcount));
1494 *statp = EX_SOFTWARE;
1500 for (ancount = ntohs((unsigned short) hp->ancount);
1501 --ancount >= 0 && ap < eom;
1504 n = dn_expand((unsigned char *) &answer, eom, ap,
1505 (RES_UNC_T) nbuf, sizeof(nbuf));
1510 ap += INT16SZ; /* skip over class */
1512 GETSHORT(n, ap); /* rdlength */
1517 if (*dp != '\0' && HasWildcardMX)
1520 ** If we are using MX matches and have
1521 ** not yet gotten one, save this one
1522 ** but keep searching for an A or
1526 if (trymx && mxmatch == NULL)
1532 ** If we did not append a domain name, this
1533 ** must have been a canonical name to start
1534 ** with. Even if we did append a domain name,
1535 ** in the absence of a wildcard MX this must
1536 ** still be a real MX match.
1537 ** Such MX matches are as good as an A match,
1546 /* Flag that a good match was found */
1549 /* continue in case a CNAME also exists */
1553 if (DontExpandCnames)
1555 /* got CNAME -- guaranteed canonical */
1560 if (loopcnt++ > MAXCNAMEDEPTH)
1562 /*XXX should notify postmaster XXX*/
1563 message("DNS failure: CNAME loop for %s",
1565 if (CurEnv->e_message == NULL)
1569 (void) sm_snprintf(ebuf,
1571 "Deferred: DNS failure: CNAME loop for %.100s",
1575 CurEnv->e_rpool, ebuf);
1577 SM_SET_H_ERRNO(NO_RECOVERY);
1582 /* value points at name */
1583 if ((ret = dn_expand((unsigned char *)&answer,
1584 eom, ap, (RES_UNC_T) nbuf,
1587 (void) sm_strlcpy(host, nbuf, hbsize);
1590 ** RFC 1034 section 3.6 specifies that CNAME
1591 ** should point at the canonical name -- but
1592 ** urges software to try again anyway.
1598 /* not a record of interest */
1606 ** Got a good match -- either an A, CNAME, or an
1607 ** exact MX record. Save it and get out of here.
1615 ** Nothing definitive yet.
1616 ** If this was a T_A query and we haven't yet found a MX
1617 ** match, try T_MX if allowed to do so.
1618 ** Otherwise, try the next domain.
1622 if (qtype == T_AAAA)
1626 if (qtype == T_A && !gotmx && (trymx || *dp == '\0'))
1635 /* if nothing was found, we are done */
1636 if (mxmatch == NULL)
1638 if (*statp == EX_OK)
1644 ** Create canonical name and return.
1645 ** If saved domain name is null, name was already canonical.
1646 ** Otherwise append the saved domain name.
1649 (void) sm_snprintf(nbuf, sizeof(nbuf), "%.*s%s%.*s", MAXDNAME, host,
1650 *mxmatch == '\0' ? "" : ".",
1652 (void) sm_strlcpy(host, nbuf, hbsize);
1654 sm_dprintf("dns_getcanonname: %s\n", host);
1657 /* return only one TTL entry, that should be sufficient */
1658 if (ttl > 0 && pttl != NULL)
1661 _res.options = old_options;
1663 return ad ? HOST_SECURE : HOST_OK;
1667 _res.options = old_options;
1669 return HOST_NOTFOUND;
1672 #endif /* NAMED_BIND */