xref: /freebsd/contrib/sendmail/src/domain.c (revision 5b0945b57059d1cde0831d3afea7ec56c7d79508)
1c2aa98e2SPeter Wemm /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 1998-2004, 2006, 2010 Proofpoint, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1986, 1995-1997 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
1406f25ae9SGregory Neil Shapiro #include <sendmail.h>
15d0cef73dSGregory Neil Shapiro #include "map.h"
16*5b0945b5SGregory Neil Shapiro #if _FFR_EAI
17*5b0945b5SGregory Neil Shapiro #include <unicode/uidna.h>
18*5b0945b5SGregory Neil Shapiro #endif
19c2aa98e2SPeter Wemm 
20c2aa98e2SPeter Wemm #if NAMED_BIND
214313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (with name server)")
22*5b0945b5SGregory Neil Shapiro #else
234313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (without name server)")
24*5b0945b5SGregory Neil Shapiro #endif
25c2aa98e2SPeter Wemm 
26c2aa98e2SPeter Wemm #if NAMED_BIND
27c2aa98e2SPeter Wemm 
28c2aa98e2SPeter Wemm # include <arpa/inet.h>
29*5b0945b5SGregory Neil Shapiro # include <sm_resolve.h>
30*5b0945b5SGregory Neil Shapiro # if DANE
31*5b0945b5SGregory Neil Shapiro #  include <tls.h>
32*5b0945b5SGregory Neil Shapiro #  ifndef SM_NEG_TTL
33*5b0945b5SGregory Neil Shapiro #   define SM_NEG_TTL 60 /* "negative" TTL */
34*5b0945b5SGregory Neil Shapiro #  endif
35*5b0945b5SGregory Neil Shapiro # endif
36c2aa98e2SPeter Wemm 
3740266059SGregory Neil Shapiro 
38c2aa98e2SPeter Wemm # ifndef MXHOSTBUFSIZE
39c2aa98e2SPeter Wemm #  define MXHOSTBUFSIZE	(128 * MAXMXHOSTS)
40*5b0945b5SGregory Neil Shapiro # endif
41c2aa98e2SPeter Wemm 
42c2aa98e2SPeter Wemm static char	MXHostBuf[MXHOSTBUFSIZE];
4340266059SGregory Neil Shapiro # if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2)
4440266059SGregory Neil Shapiro 	ERROR: _MXHOSTBUFSIZE is out of range
45*5b0945b5SGregory Neil Shapiro # endif
46c2aa98e2SPeter Wemm 
47c2aa98e2SPeter Wemm # ifndef MAXDNSRCH
48c2aa98e2SPeter Wemm #  define MAXDNSRCH	6	/* number of possible domains to search */
49*5b0945b5SGregory Neil Shapiro # endif
5006f25ae9SGregory Neil Shapiro 
5106f25ae9SGregory Neil Shapiro # ifndef RES_DNSRCH_VARIABLE
5206f25ae9SGregory Neil Shapiro #  define RES_DNSRCH_VARIABLE	_res.dnsrch
53*5b0945b5SGregory Neil Shapiro # endif
54c2aa98e2SPeter Wemm 
55c2aa98e2SPeter Wemm # ifndef NO_DATA
56c2aa98e2SPeter Wemm #  define NO_DATA	NO_ADDRESS
57*5b0945b5SGregory Neil Shapiro # endif
58c2aa98e2SPeter Wemm 
59c2aa98e2SPeter Wemm # ifndef HFIXEDSZ
60c2aa98e2SPeter Wemm #  define HFIXEDSZ	12	/* sizeof(HEADER) */
61*5b0945b5SGregory Neil Shapiro # endif
62c2aa98e2SPeter Wemm 
63c2aa98e2SPeter Wemm # define MAXCNAMEDEPTH	10	/* maximum depth of CNAME recursion */
64c2aa98e2SPeter Wemm 
65c2aa98e2SPeter Wemm # if defined(__RES) && (__RES >= 19940415)
66c2aa98e2SPeter Wemm #  define RES_UNC_T	char *
67*5b0945b5SGregory Neil Shapiro # else
6840266059SGregory Neil Shapiro #  define RES_UNC_T	unsigned char *
69*5b0945b5SGregory Neil Shapiro # endif
7006f25ae9SGregory Neil Shapiro 
7106f25ae9SGregory Neil Shapiro static int	mxrand __P((char *));
7240266059SGregory Neil Shapiro static int	fallbackmxrr __P((int, unsigned short *, char **));
7306f25ae9SGregory Neil Shapiro 
74*5b0945b5SGregory Neil Shapiro # if DANE
75*5b0945b5SGregory Neil Shapiro 
76*5b0945b5SGregory Neil Shapiro /*
77*5b0945b5SGregory Neil Shapiro **  TLSAADD -- add TLSA records to dane_tlsa entry
78*5b0945b5SGregory Neil Shapiro **
79*5b0945b5SGregory Neil Shapiro **	Parameters:
80*5b0945b5SGregory Neil Shapiro **		name -- key for stab entry (for debugging output)
81*5b0945b5SGregory Neil Shapiro **		dr -- DNS reply
82*5b0945b5SGregory Neil Shapiro **		dane_tlsa -- dane_tlsa entry
83*5b0945b5SGregory Neil Shapiro **		dnsrc -- DNS lookup return code (h_errno)
84*5b0945b5SGregory Neil Shapiro **		n -- current number of TLSA records in dane_tlsa entry
85*5b0945b5SGregory Neil Shapiro **		pttl -- (pointer to) TTL (in/out)
86*5b0945b5SGregory Neil Shapiro **		level -- recursion level (CNAMEs)
87*5b0945b5SGregory Neil Shapiro **
88*5b0945b5SGregory Neil Shapiro **	Returns:
89*5b0945b5SGregory Neil Shapiro **		new number of TLSA records
90*5b0945b5SGregory Neil Shapiro */
91*5b0945b5SGregory Neil Shapiro 
92*5b0945b5SGregory Neil Shapiro static int tlsaadd __P((const char *, DNS_REPLY_T *, dane_tlsa_P, int, int,
93*5b0945b5SGregory Neil Shapiro 			unsigned int *, int));
94*5b0945b5SGregory Neil Shapiro 
95*5b0945b5SGregory Neil Shapiro static int
96*5b0945b5SGregory Neil Shapiro tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
97*5b0945b5SGregory Neil Shapiro 	const char *name;
98*5b0945b5SGregory Neil Shapiro 	DNS_REPLY_T *dr;
99*5b0945b5SGregory Neil Shapiro 	dane_tlsa_P dane_tlsa;
100*5b0945b5SGregory Neil Shapiro 	int dnsrc;
101*5b0945b5SGregory Neil Shapiro 	int n;
102*5b0945b5SGregory Neil Shapiro 	unsigned int *pttl;
103*5b0945b5SGregory Neil Shapiro 	int level;
104*5b0945b5SGregory Neil Shapiro {
105*5b0945b5SGregory Neil Shapiro 	RESOURCE_RECORD_T *rr;
106*5b0945b5SGregory Neil Shapiro 	unsigned int ttl;
107*5b0945b5SGregory Neil Shapiro 	int nprev;
108*5b0945b5SGregory Neil Shapiro 
109*5b0945b5SGregory Neil Shapiro 	if (dnsrc != 0)
110*5b0945b5SGregory Neil Shapiro 	{
111*5b0945b5SGregory Neil Shapiro 		if (tTd(8, 2))
112*5b0945b5SGregory Neil Shapiro 			sm_dprintf("tlsaadd(%s), prev=%d, dnsrc=%d\n",
113*5b0945b5SGregory Neil Shapiro 				name, dane_tlsa->dane_tlsa_dnsrc, dnsrc);
114*5b0945b5SGregory Neil Shapiro 
115*5b0945b5SGregory Neil Shapiro 		/* check previous error and keep the "most important" one? */
116*5b0945b5SGregory Neil Shapiro 		dane_tlsa->dane_tlsa_dnsrc = dnsrc;
117*5b0945b5SGregory Neil Shapiro # if DNSSEC_TEST
118*5b0945b5SGregory Neil Shapiro 		if (tTd(8, 110))
119*5b0945b5SGregory Neil Shapiro 			*pttl = tTdlevel(8)-110;	/* how to make this an option? */
120*5b0945b5SGregory Neil Shapiro 		else
121*5b0945b5SGregory Neil Shapiro # else
122*5b0945b5SGregory Neil Shapiro 			*pttl = SM_NEG_TTL;
123*5b0945b5SGregory Neil Shapiro # endif
124*5b0945b5SGregory Neil Shapiro 
125*5b0945b5SGregory Neil Shapiro 		return n;
126*5b0945b5SGregory Neil Shapiro 	}
127*5b0945b5SGregory Neil Shapiro 	if (dr == NULL)
128*5b0945b5SGregory Neil Shapiro 		return n;
129*5b0945b5SGregory Neil Shapiro 	if (dr->dns_r_h.ad != 1 && Dane == DANE_SECURE)	/* not secure? */
130*5b0945b5SGregory Neil Shapiro 		return n;
131*5b0945b5SGregory Neil Shapiro 	ttl = *pttl;
132*5b0945b5SGregory Neil Shapiro 
133*5b0945b5SGregory Neil Shapiro 	/* first: try to find TLSA records */
134*5b0945b5SGregory Neil Shapiro 	nprev = n;
135*5b0945b5SGregory Neil Shapiro 	for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR;
136*5b0945b5SGregory Neil Shapiro 	     rr = rr->rr_next)
137*5b0945b5SGregory Neil Shapiro 	{
138*5b0945b5SGregory Neil Shapiro 		int tlsa_chk;
139*5b0945b5SGregory Neil Shapiro 
140*5b0945b5SGregory Neil Shapiro 		if (rr->rr_type != T_TLSA)
141*5b0945b5SGregory Neil Shapiro 		{
142*5b0945b5SGregory Neil Shapiro 			if (rr->rr_type != T_CNAME && tTd(8, 8))
143*5b0945b5SGregory Neil Shapiro 				sm_dprintf("tlsaadd(%s), type=%s\n", name,
144*5b0945b5SGregory Neil Shapiro 					dns_type_to_string(rr->rr_type));
145*5b0945b5SGregory Neil Shapiro 			continue;
146*5b0945b5SGregory Neil Shapiro 		}
147*5b0945b5SGregory Neil Shapiro 		tlsa_chk = dane_tlsa_chk(rr->rr_u.rr_data, rr->rr_size, name,
148*5b0945b5SGregory Neil Shapiro 					true);
149*5b0945b5SGregory Neil Shapiro 		if (!TLSA_IS_VALID(tlsa_chk))
150*5b0945b5SGregory Neil Shapiro 			continue;
151*5b0945b5SGregory Neil Shapiro 
152*5b0945b5SGregory Neil Shapiro 		/*
153*5b0945b5SGregory Neil Shapiro 		**  To do: the RRs should be sorted (by "complexity") --
154*5b0945b5SGregory Neil Shapiro 		**  when more than one type is supported.
155*5b0945b5SGregory Neil Shapiro 		*/
156*5b0945b5SGregory Neil Shapiro 
157*5b0945b5SGregory Neil Shapiro 		dane_tlsa->dane_tlsa_rr[n] = rr->rr_u.rr_data;
158*5b0945b5SGregory Neil Shapiro 		dane_tlsa->dane_tlsa_len[n] = rr->rr_size;
159*5b0945b5SGregory Neil Shapiro 		if (tTd(8, 2))
160*5b0945b5SGregory Neil Shapiro 		{
161*5b0945b5SGregory Neil Shapiro 			unsigned char *p;
162*5b0945b5SGregory Neil Shapiro 
163*5b0945b5SGregory Neil Shapiro 			p = rr->rr_u.rr_data;
164*5b0945b5SGregory Neil Shapiro 			sm_dprintf("tlsaadd(%s), n=%d, %d-%d-%d:%02x\n", name,
165*5b0945b5SGregory Neil Shapiro 				n, (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
166*5b0945b5SGregory Neil Shapiro 		}
167*5b0945b5SGregory Neil Shapiro 
168*5b0945b5SGregory Neil Shapiro 		/* require some minimum TTL? */
169*5b0945b5SGregory Neil Shapiro 		if (ttl > rr->rr_ttl && rr->rr_ttl > 0)
170*5b0945b5SGregory Neil Shapiro 			ttl = rr->rr_ttl;
171*5b0945b5SGregory Neil Shapiro 
172*5b0945b5SGregory Neil Shapiro 		/* hack: instead of copying the data, just "take it over" */
173*5b0945b5SGregory Neil Shapiro 		rr->rr_u.rr_data = NULL;
174*5b0945b5SGregory Neil Shapiro 		++n;
175*5b0945b5SGregory Neil Shapiro 	}
176*5b0945b5SGregory Neil Shapiro 
177*5b0945b5SGregory Neil Shapiro 	/* second: check for CNAME records, but only if no TLSA RR was added */
178*5b0945b5SGregory Neil Shapiro 	for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR && nprev == n;
179*5b0945b5SGregory Neil Shapiro 	     rr = rr->rr_next)
180*5b0945b5SGregory Neil Shapiro 	{
181*5b0945b5SGregory Neil Shapiro 		DNS_REPLY_T *drc;
182*5b0945b5SGregory Neil Shapiro 		int err, herr;
183*5b0945b5SGregory Neil Shapiro 
184*5b0945b5SGregory Neil Shapiro 		if (rr->rr_type != T_CNAME)
185*5b0945b5SGregory Neil Shapiro 			continue;
186*5b0945b5SGregory Neil Shapiro 		if (level > 1)
187*5b0945b5SGregory Neil Shapiro 		{
188*5b0945b5SGregory Neil Shapiro 			if (tTd(8, 2))
189*5b0945b5SGregory Neil Shapiro 				sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d\n",
190*5b0945b5SGregory Neil Shapiro 					name, rr->rr_u.rr_txt, level);
191*5b0945b5SGregory Neil Shapiro 			continue;
192*5b0945b5SGregory Neil Shapiro 		}
193*5b0945b5SGregory Neil Shapiro 
194*5b0945b5SGregory Neil Shapiro 		drc = dns_lookup_int(rr->rr_u.rr_txt, C_IN, T_TLSA, 0, 0,
195*5b0945b5SGregory Neil Shapiro 			(Dane == DANE_SECURE &&
196*5b0945b5SGregory Neil Shapiro 			 !TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX))
197*5b0945b5SGregory Neil Shapiro 			? SM_RES_DNSSEC : 0,
198*5b0945b5SGregory Neil Shapiro 			RR_RAW, &err, &herr);
199*5b0945b5SGregory Neil Shapiro 
200*5b0945b5SGregory Neil Shapiro 		if (tTd(8, 2))
201*5b0945b5SGregory Neil Shapiro 			sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d, dr=%p, ad=%d, err=%d, herr=%d\n",
202*5b0945b5SGregory Neil Shapiro 				name, rr->rr_u.rr_txt, level,
203*5b0945b5SGregory Neil Shapiro 				(void *)drc, drc != NULL ? drc->dns_r_h.ad : -1,
204*5b0945b5SGregory Neil Shapiro 				err, herr);
205*5b0945b5SGregory Neil Shapiro 		nprev = n = tlsaadd(name, drc, dane_tlsa, herr, n, pttl,
206*5b0945b5SGregory Neil Shapiro 				level + 1);
207*5b0945b5SGregory Neil Shapiro 		dns_free_data(drc);
208*5b0945b5SGregory Neil Shapiro 		drc = NULL;
209*5b0945b5SGregory Neil Shapiro 	}
210*5b0945b5SGregory Neil Shapiro 
211*5b0945b5SGregory Neil Shapiro 	*pttl = ttl;
212*5b0945b5SGregory Neil Shapiro 	return n;
213*5b0945b5SGregory Neil Shapiro }
214*5b0945b5SGregory Neil Shapiro 
215*5b0945b5SGregory Neil Shapiro /*
216*5b0945b5SGregory Neil Shapiro **  GETTLSA -- get TLSA records for named host using DNS
217*5b0945b5SGregory Neil Shapiro **
218*5b0945b5SGregory Neil Shapiro **	Parameters:
219*5b0945b5SGregory Neil Shapiro **		host -- host
220*5b0945b5SGregory Neil Shapiro **		name -- name for stab entry key (if NULL: host)
221*5b0945b5SGregory Neil Shapiro **		pste -- (pointer to) stab entry (output)
222*5b0945b5SGregory Neil Shapiro **		flags -- TLSAFL*
223*5b0945b5SGregory Neil Shapiro **		mxttl -- TTL of MX (or host)
224*5b0945b5SGregory Neil Shapiro **		port -- port
225*5b0945b5SGregory Neil Shapiro **
226*5b0945b5SGregory Neil Shapiro **	Returns:
227*5b0945b5SGregory Neil Shapiro **		The number of TLSA records found.
228*5b0945b5SGregory Neil Shapiro **		<0 if there is an internal failure.
229*5b0945b5SGregory Neil Shapiro **
230*5b0945b5SGregory Neil Shapiro **	Side effects:
231*5b0945b5SGregory Neil Shapiro **		Enters TLSA RRs into stab().
232*5b0945b5SGregory Neil Shapiro **		If the DNS lookup fails temporarily, an "empty" entry is
233*5b0945b5SGregory Neil Shapiro **		created with that DNS error code.
234*5b0945b5SGregory Neil Shapiro */
235*5b0945b5SGregory Neil Shapiro 
236*5b0945b5SGregory Neil Shapiro int
237*5b0945b5SGregory Neil Shapiro gettlsa(host, name, pste, flags, mxttl, port)
238*5b0945b5SGregory Neil Shapiro 	char *host;
239*5b0945b5SGregory Neil Shapiro 	char *name;
240*5b0945b5SGregory Neil Shapiro 	STAB **pste;
241*5b0945b5SGregory Neil Shapiro 	unsigned long flags;
242*5b0945b5SGregory Neil Shapiro 	unsigned int mxttl;
243*5b0945b5SGregory Neil Shapiro 	unsigned int port;
244*5b0945b5SGregory Neil Shapiro {
245*5b0945b5SGregory Neil Shapiro 	DNS_REPLY_T *dr;
246*5b0945b5SGregory Neil Shapiro 	dane_tlsa_P dane_tlsa;
247*5b0945b5SGregory Neil Shapiro 	STAB *ste;
248*5b0945b5SGregory Neil Shapiro 	time_t now;
249*5b0945b5SGregory Neil Shapiro 	unsigned int ttl;
250*5b0945b5SGregory Neil Shapiro 	int n_rrs, len, err, herr;
251*5b0945b5SGregory Neil Shapiro 	bool isrname;
252*5b0945b5SGregory Neil Shapiro 	char nbuf[MAXDNAME];
253*5b0945b5SGregory Neil Shapiro 	char key[MAXDNAME];
254*5b0945b5SGregory Neil Shapiro 
255*5b0945b5SGregory Neil Shapiro 	SM_REQUIRE(host != NULL);
256*5b0945b5SGregory Neil Shapiro 	if (pste != NULL)
257*5b0945b5SGregory Neil Shapiro 		*pste = NULL;
258*5b0945b5SGregory Neil Shapiro 	if ('\0' == *host)
259*5b0945b5SGregory Neil Shapiro 		return 0;
260*5b0945b5SGregory Neil Shapiro 
261*5b0945b5SGregory Neil Shapiro 	isrname = NULL == name;
262*5b0945b5SGregory Neil Shapiro 	if (isrname)
263*5b0945b5SGregory Neil Shapiro 		name = host;
264*5b0945b5SGregory Neil Shapiro 	now = 0;
265*5b0945b5SGregory Neil Shapiro 	n_rrs = 0;
266*5b0945b5SGregory Neil Shapiro 	dr = NULL;
267*5b0945b5SGregory Neil Shapiro 	dane_tlsa = NULL;
268*5b0945b5SGregory Neil Shapiro 	len = strlen(name);
269*5b0945b5SGregory Neil Shapiro 	if (len > 1 && name[len - 1] == '.')
270*5b0945b5SGregory Neil Shapiro 	{
271*5b0945b5SGregory Neil Shapiro 		len--;
272*5b0945b5SGregory Neil Shapiro 		name[len] = '\0';
273*5b0945b5SGregory Neil Shapiro 	}
274*5b0945b5SGregory Neil Shapiro 	else
275*5b0945b5SGregory Neil Shapiro 		len = -1;
276*5b0945b5SGregory Neil Shapiro 	if (0 == port || tTd(66, 10))
277*5b0945b5SGregory Neil Shapiro 		port = 25;
278*5b0945b5SGregory Neil Shapiro 	(void) sm_snprintf(key, sizeof(key), "_%u..%s", port, name);
279*5b0945b5SGregory Neil Shapiro 	ste = stab(key, ST_TLSA_RR, ST_FIND);
280*5b0945b5SGregory Neil Shapiro 	if (tTd(8, 2))
281*5b0945b5SGregory Neil Shapiro 		sm_dprintf("gettlsa(%s, %s, ste=%p, pste=%p, flags=%lX, port=%d)\n",
282*5b0945b5SGregory Neil Shapiro 			host, isrname ? "" : name, (void *)ste, (void *)pste,
283*5b0945b5SGregory Neil Shapiro 			flags, port);
284*5b0945b5SGregory Neil Shapiro 
285*5b0945b5SGregory Neil Shapiro 	if (ste != NULL)
286*5b0945b5SGregory Neil Shapiro 	{
287*5b0945b5SGregory Neil Shapiro 		dane_tlsa = ste->s_tlsa;
288*5b0945b5SGregory Neil Shapiro 		if ((TLSAFLADMX & flags) != 0)
289*5b0945b5SGregory Neil Shapiro 			TLSA_CLR_FL(ste->s_tlsa, TLSAFLNOADMX);
290*5b0945b5SGregory Neil Shapiro 	}
291*5b0945b5SGregory Neil Shapiro 
292*5b0945b5SGregory Neil Shapiro 	/* Do not reload TLSA RRs if the MX RRs were not securely retrieved. */
293*5b0945b5SGregory Neil Shapiro 	if (pste != NULL
294*5b0945b5SGregory Neil Shapiro 	    && dane_tlsa != NULL && TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX)
295*5b0945b5SGregory Neil Shapiro 	    && DANE_SECURE == Dane)
296*5b0945b5SGregory Neil Shapiro 		goto end;
297*5b0945b5SGregory Neil Shapiro 
298*5b0945b5SGregory Neil Shapiro 	if (ste != NULL)
299*5b0945b5SGregory Neil Shapiro 	{
300*5b0945b5SGregory Neil Shapiro 		SM_ASSERT(dane_tlsa != NULL);
301*5b0945b5SGregory Neil Shapiro 		now = curtime();
302*5b0945b5SGregory Neil Shapiro 		if (dane_tlsa->dane_tlsa_exp <= now
303*5b0945b5SGregory Neil Shapiro 		    && 0 == (TLSAFLNOEXP & flags))
304*5b0945b5SGregory Neil Shapiro 			dane_tlsa_clr(dane_tlsa);
305*5b0945b5SGregory Neil Shapiro 		else
306*5b0945b5SGregory Neil Shapiro 		{
307*5b0945b5SGregory Neil Shapiro 			n_rrs = dane_tlsa->dane_tlsa_n;
308*5b0945b5SGregory Neil Shapiro 			goto end;
309*5b0945b5SGregory Neil Shapiro 		}
310*5b0945b5SGregory Neil Shapiro 	}
311*5b0945b5SGregory Neil Shapiro 
312*5b0945b5SGregory Neil Shapiro 	if (dane_tlsa == NULL)
313*5b0945b5SGregory Neil Shapiro 	{
314*5b0945b5SGregory Neil Shapiro 		dane_tlsa = (dane_tlsa_P) sm_malloc(sizeof(*dane_tlsa));
315*5b0945b5SGregory Neil Shapiro 		if (dane_tlsa == NULL)
316*5b0945b5SGregory Neil Shapiro 		{
317*5b0945b5SGregory Neil Shapiro 			n_rrs = -ENOMEM;
318*5b0945b5SGregory Neil Shapiro 			goto end;
319*5b0945b5SGregory Neil Shapiro 		}
320*5b0945b5SGregory Neil Shapiro 		memset(dane_tlsa, '\0', sizeof(*dane_tlsa));
321*5b0945b5SGregory Neil Shapiro 	}
322*5b0945b5SGregory Neil Shapiro 
323*5b0945b5SGregory Neil Shapiro 	/* There are flags to store -- just set those, do nothing else. */
324*5b0945b5SGregory Neil Shapiro 	if (TLSA_STORE_FL(flags))
325*5b0945b5SGregory Neil Shapiro 	{
326*5b0945b5SGregory Neil Shapiro 		dane_tlsa->dane_tlsa_flags = flags;
327*5b0945b5SGregory Neil Shapiro 		ttl = mxttl > 0 ? mxttl: SM_DEFAULT_TTL;
328*5b0945b5SGregory Neil Shapiro 		goto done;
329*5b0945b5SGregory Neil Shapiro 	}
330*5b0945b5SGregory Neil Shapiro 
331*5b0945b5SGregory Neil Shapiro 	(void) sm_snprintf(nbuf, sizeof(nbuf), "_%u._tcp.%s", port, host);
332*5b0945b5SGregory Neil Shapiro 	dr = dns_lookup_int(nbuf, C_IN, T_TLSA, 0, 0,
333*5b0945b5SGregory Neil Shapiro 		TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX) ? 0 : SM_RES_DNSSEC,
334*5b0945b5SGregory Neil Shapiro 		RR_RAW, &err, &herr);
335*5b0945b5SGregory Neil Shapiro 	if (tTd(8, 2))
336*5b0945b5SGregory Neil Shapiro 		sm_dprintf("gettlsa(%s), dr=%p, ad=%d, err=%d, herr=%d\n", host,
337*5b0945b5SGregory Neil Shapiro 			(void *)dr, dr != NULL ? dr->dns_r_h.ad : -1, err, herr);
338*5b0945b5SGregory Neil Shapiro 	ttl = UINT_MAX;
339*5b0945b5SGregory Neil Shapiro 	n_rrs = tlsaadd(key, dr, dane_tlsa, herr, n_rrs, &ttl, 0);
340*5b0945b5SGregory Neil Shapiro 
341*5b0945b5SGregory Neil Shapiro 	/* no valid entries found? */
342*5b0945b5SGregory Neil Shapiro 	if (n_rrs == 0 && !TLSA_RR_TEMPFAIL(dane_tlsa))
343*5b0945b5SGregory Neil Shapiro 	{
344*5b0945b5SGregory Neil Shapiro 		if (tTd(8, 2))
345*5b0945b5SGregory Neil Shapiro 			sm_dprintf("gettlsa(%s), n_rrs=%d, herr=%d, status=NOT_ADDED\n",
346*5b0945b5SGregory Neil Shapiro 				host, n_rrs, dane_tlsa->dane_tlsa_dnsrc);
347*5b0945b5SGregory Neil Shapiro 		goto cleanup;
348*5b0945b5SGregory Neil Shapiro 	}
349*5b0945b5SGregory Neil Shapiro 
350*5b0945b5SGregory Neil Shapiro   done:
351*5b0945b5SGregory Neil Shapiro 	dane_tlsa->dane_tlsa_n = n_rrs;
352*5b0945b5SGregory Neil Shapiro 	if (!isrname)
353*5b0945b5SGregory Neil Shapiro 	{
354*5b0945b5SGregory Neil Shapiro 		SM_FREE(dane_tlsa->dane_tlsa_sni);
355*5b0945b5SGregory Neil Shapiro 		dane_tlsa->dane_tlsa_sni = sm_strdup(host);
356*5b0945b5SGregory Neil Shapiro 	}
357*5b0945b5SGregory Neil Shapiro 	if (NULL == ste)
358*5b0945b5SGregory Neil Shapiro 	{
359*5b0945b5SGregory Neil Shapiro 		ste = stab(key, ST_TLSA_RR, ST_ENTER);
360*5b0945b5SGregory Neil Shapiro 		if (NULL == ste)
361*5b0945b5SGregory Neil Shapiro 			goto error;
362*5b0945b5SGregory Neil Shapiro 	}
363*5b0945b5SGregory Neil Shapiro 	ste->s_tlsa = dane_tlsa;
364*5b0945b5SGregory Neil Shapiro 	if (now == 0)
365*5b0945b5SGregory Neil Shapiro 		now = curtime();
366*5b0945b5SGregory Neil Shapiro 	dane_tlsa->dane_tlsa_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL);
367*5b0945b5SGregory Neil Shapiro 	dns_free_data(dr);
368*5b0945b5SGregory Neil Shapiro 	dr = NULL;
369*5b0945b5SGregory Neil Shapiro 	goto end;
370*5b0945b5SGregory Neil Shapiro 
371*5b0945b5SGregory Neil Shapiro   error:
372*5b0945b5SGregory Neil Shapiro 	if (tTd(8, 2))
373*5b0945b5SGregory Neil Shapiro 		sm_dprintf("gettlsa(%s, %s), status=error\n", host, key);
374*5b0945b5SGregory Neil Shapiro 	n_rrs = -1;
375*5b0945b5SGregory Neil Shapiro   cleanup:
376*5b0945b5SGregory Neil Shapiro 	if (NULL == ste)
377*5b0945b5SGregory Neil Shapiro 		dane_tlsa_free(dane_tlsa);
378*5b0945b5SGregory Neil Shapiro 	dns_free_data(dr);
379*5b0945b5SGregory Neil Shapiro 	dr = NULL;
380*5b0945b5SGregory Neil Shapiro 
381*5b0945b5SGregory Neil Shapiro   end:
382*5b0945b5SGregory Neil Shapiro 	if (pste != NULL && ste != NULL)
383*5b0945b5SGregory Neil Shapiro 		*pste = ste;
384*5b0945b5SGregory Neil Shapiro 	if (len > 0)
385*5b0945b5SGregory Neil Shapiro 		host[len] = '.';
386*5b0945b5SGregory Neil Shapiro 	return n_rrs;
387*5b0945b5SGregory Neil Shapiro }
388*5b0945b5SGregory Neil Shapiro # endif /* DANE */
389*5b0945b5SGregory Neil Shapiro 
39040266059SGregory Neil Shapiro /*
39140266059SGregory Neil Shapiro **  GETFALLBACKMXRR -- get MX resource records for fallback MX host.
39240266059SGregory Neil Shapiro **
39340266059SGregory Neil Shapiro **	We have to initialize this once before doing anything else.
39440266059SGregory Neil Shapiro **	Moreover, we have to repeat this from time to time to avoid
39540266059SGregory Neil Shapiro **	stale data, e.g., in persistent queue runners.
39640266059SGregory Neil Shapiro **	This should be done in a parent process so the child
39740266059SGregory Neil Shapiro **	processes have the right data.
39840266059SGregory Neil Shapiro **
39940266059SGregory Neil Shapiro **	Parameters:
40040266059SGregory Neil Shapiro **		host -- the name of the fallback MX host.
40140266059SGregory Neil Shapiro **
40240266059SGregory Neil Shapiro **	Returns:
40340266059SGregory Neil Shapiro **		number of MX records.
40440266059SGregory Neil Shapiro **
40540266059SGregory Neil Shapiro **	Side Effects:
406e92d3f3fSGregory Neil Shapiro **		Populates NumFallbackMXHosts and fbhosts.
40740266059SGregory Neil Shapiro **		Sets renewal time (based on TTL).
40840266059SGregory Neil Shapiro */
40940266059SGregory Neil Shapiro 
410e92d3f3fSGregory Neil Shapiro int NumFallbackMXHosts = 0;	/* Number of fallback MX hosts (after MX expansion) */
41140266059SGregory Neil Shapiro static char *fbhosts[MAXMXHOSTS + 1];
41240266059SGregory Neil Shapiro 
41340266059SGregory Neil Shapiro int
41440266059SGregory Neil Shapiro getfallbackmxrr(host)
41540266059SGregory Neil Shapiro 	char *host;
41640266059SGregory Neil Shapiro {
41740266059SGregory Neil Shapiro 	int i, rcode;
41840266059SGregory Neil Shapiro 	int ttl;
41940266059SGregory Neil Shapiro 	static time_t renew = 0;
42040266059SGregory Neil Shapiro 
42140266059SGregory Neil Shapiro #if 0
42240266059SGregory Neil Shapiro 	/* This is currently done before this function is called. */
42340266059SGregory Neil Shapiro 	if (host == NULL || *host == '\0')
42440266059SGregory Neil Shapiro 		return 0;
42540266059SGregory Neil Shapiro #endif /* 0 */
426e92d3f3fSGregory Neil Shapiro 	if (NumFallbackMXHosts > 0 && renew > curtime())
427e92d3f3fSGregory Neil Shapiro 		return NumFallbackMXHosts;
428*5b0945b5SGregory Neil Shapiro 
429*5b0945b5SGregory Neil Shapiro 	/* for DANE we need to invoke getmxrr() to get the TLSA RRs. */
430*5b0945b5SGregory Neil Shapiro #if !DANE
43140266059SGregory Neil Shapiro 	if (host[0] == '[')
43240266059SGregory Neil Shapiro 	{
43340266059SGregory Neil Shapiro 		fbhosts[0] = host;
434e92d3f3fSGregory Neil Shapiro 		NumFallbackMXHosts = 1;
43540266059SGregory Neil Shapiro 	}
43640266059SGregory Neil Shapiro 	else
437*5b0945b5SGregory Neil Shapiro #endif
43840266059SGregory Neil Shapiro 	{
43940266059SGregory Neil Shapiro 		/* free old data */
440e92d3f3fSGregory Neil Shapiro 		for (i = 0; i < NumFallbackMXHosts; i++)
44140266059SGregory Neil Shapiro 			sm_free(fbhosts[i]);
44240266059SGregory Neil Shapiro 
443*5b0945b5SGregory Neil Shapiro 		/*
444*5b0945b5SGregory Neil Shapiro 		**  Get new data.
445*5b0945b5SGregory Neil Shapiro 		**  Note: passing 0 as port is not correct but we cannot
446*5b0945b5SGregory Neil Shapiro 		**  determine the port number as there is no mailer.
447*5b0945b5SGregory Neil Shapiro 		*/
448*5b0945b5SGregory Neil Shapiro 
449*5b0945b5SGregory Neil Shapiro 		NumFallbackMXHosts = getmxrr(host, fbhosts, NULL,
450*5b0945b5SGregory Neil Shapiro #if DANE
451*5b0945b5SGregory Neil Shapiro 					(DANE_SECURE == Dane) ?  ISAD :
452*5b0945b5SGregory Neil Shapiro #endif
453*5b0945b5SGregory Neil Shapiro 					0,
454*5b0945b5SGregory Neil Shapiro 					&rcode, &ttl, 0);
45540266059SGregory Neil Shapiro 		renew = curtime() + ttl;
456e92d3f3fSGregory Neil Shapiro 		for (i = 0; i < NumFallbackMXHosts; i++)
45740266059SGregory Neil Shapiro 			fbhosts[i] = newstr(fbhosts[i]);
45840266059SGregory Neil Shapiro 	}
459*5b0945b5SGregory Neil Shapiro 	if (NumFallbackMXHosts == NULLMX)
460*5b0945b5SGregory Neil Shapiro 		NumFallbackMXHosts = 0;
461e92d3f3fSGregory Neil Shapiro 	return NumFallbackMXHosts;
46240266059SGregory Neil Shapiro }
46340266059SGregory Neil Shapiro 
46440266059SGregory Neil Shapiro /*
46540266059SGregory Neil Shapiro **  FALLBACKMXRR -- add MX resource records for fallback MX host to list.
46640266059SGregory Neil Shapiro **
46740266059SGregory Neil Shapiro **	Parameters:
46840266059SGregory Neil Shapiro **		nmx -- current number of MX records.
46940266059SGregory Neil Shapiro **		prefs -- array of preferences.
47040266059SGregory Neil Shapiro **		mxhosts -- array of MX hosts (maximum size: MAXMXHOSTS)
47140266059SGregory Neil Shapiro **
47240266059SGregory Neil Shapiro **	Returns:
47340266059SGregory Neil Shapiro **		new number of MX records.
47440266059SGregory Neil Shapiro **
47540266059SGregory Neil Shapiro **	Side Effects:
476e92d3f3fSGregory Neil Shapiro **		If FallbackMX was set, it appends the MX records for
47740266059SGregory Neil Shapiro **		that host to mxhosts (and modifies prefs accordingly).
47840266059SGregory Neil Shapiro */
47940266059SGregory Neil Shapiro 
48040266059SGregory Neil Shapiro static int
48140266059SGregory Neil Shapiro fallbackmxrr(nmx, prefs, mxhosts)
48240266059SGregory Neil Shapiro 	int nmx;
48340266059SGregory Neil Shapiro 	unsigned short *prefs;
48440266059SGregory Neil Shapiro 	char **mxhosts;
48540266059SGregory Neil Shapiro {
48640266059SGregory Neil Shapiro 	int i;
48740266059SGregory Neil Shapiro 
488e92d3f3fSGregory Neil Shapiro 	for (i = 0; i < NumFallbackMXHosts && nmx < MAXMXHOSTS; i++)
48940266059SGregory Neil Shapiro 	{
49040266059SGregory Neil Shapiro 		if (nmx > 0)
49140266059SGregory Neil Shapiro 			prefs[nmx] = prefs[nmx - 1] + 1;
49240266059SGregory Neil Shapiro 		else
49340266059SGregory Neil Shapiro 			prefs[nmx] = 0;
49440266059SGregory Neil Shapiro 		mxhosts[nmx++] = fbhosts[i];
49540266059SGregory Neil Shapiro 	}
49640266059SGregory Neil Shapiro 	return nmx;
49740266059SGregory Neil Shapiro }
49840266059SGregory Neil Shapiro 
49940266059SGregory Neil Shapiro /*
500c2aa98e2SPeter Wemm **  GETMXRR -- get MX resource records for a domain
501c2aa98e2SPeter Wemm **
502c2aa98e2SPeter Wemm **	Parameters:
503c2aa98e2SPeter Wemm **		host -- the name of the host to MX.
504c2aa98e2SPeter Wemm **		mxhosts -- a pointer to a return buffer of MX records.
50506f25ae9SGregory Neil Shapiro **		mxprefs -- a pointer to a return buffer of MX preferences.
50606f25ae9SGregory Neil Shapiro **			If NULL, don't try to populate.
507*5b0945b5SGregory Neil Shapiro **		flags -- flags:
508*5b0945b5SGregory Neil Shapiro **			DROPLOCALHOSt -- If true, all MX records less preferred
509c2aa98e2SPeter Wemm **			than the local host (as determined by $=w) will
510c2aa98e2SPeter Wemm **			be discarded.
511*5b0945b5SGregory Neil Shapiro **			TRYFALLBACK -- add also fallback MX host?
512*5b0945b5SGregory Neil Shapiro **			ISAD -- host lookup was secure?
513c2aa98e2SPeter Wemm **		rcode -- a pointer to an EX_ status code.
51440266059SGregory Neil Shapiro **		pttl -- pointer to return TTL (can be NULL).
515c2aa98e2SPeter Wemm **
516c2aa98e2SPeter Wemm **	Returns:
517c2aa98e2SPeter Wemm **		The number of MX records found.
518c2aa98e2SPeter Wemm **		-1 if there is an internal failure.
519c2aa98e2SPeter Wemm **		If no MX records are found, mxhosts[0] is set to host
520c2aa98e2SPeter Wemm **			and 1 is returned.
52140266059SGregory Neil Shapiro **
52240266059SGregory Neil Shapiro **	Side Effects:
52340266059SGregory Neil Shapiro **		The entries made for mxhosts point to a static array
52440266059SGregory Neil Shapiro **		MXHostBuf[MXHOSTBUFSIZE], so the data needs to be copied,
52540266059SGregory Neil Shapiro **		if it must be preserved across calls to this function.
526c2aa98e2SPeter Wemm */
527c2aa98e2SPeter Wemm 
528c2aa98e2SPeter Wemm int
529*5b0945b5SGregory Neil Shapiro getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
530c2aa98e2SPeter Wemm 	char *host;
531c2aa98e2SPeter Wemm 	char **mxhosts;
53240266059SGregory Neil Shapiro 	unsigned short *mxprefs;
533*5b0945b5SGregory Neil Shapiro 	unsigned int flags;
534c2aa98e2SPeter Wemm 	int *rcode;
53540266059SGregory Neil Shapiro 	int *pttl;
536*5b0945b5SGregory Neil Shapiro 	int port;
537c2aa98e2SPeter Wemm {
53840266059SGregory Neil Shapiro 	register unsigned char *eom, *cp;
539c2aa98e2SPeter Wemm 	register int i, j, n;
540c2aa98e2SPeter Wemm 	int nmx = 0;
541c2aa98e2SPeter Wemm 	register char *bp;
542c2aa98e2SPeter Wemm 	HEADER *hp;
543c2aa98e2SPeter Wemm 	querybuf answer;
544c2aa98e2SPeter Wemm 	int ancount, qdcount, buflen;
54540266059SGregory Neil Shapiro 	bool seenlocal = false;
54640266059SGregory Neil Shapiro 	unsigned short pref, type;
54740266059SGregory Neil Shapiro 	unsigned short localpref = 256;
548e92d3f3fSGregory Neil Shapiro 	char *fallbackMX = FallbackMX;
54940266059SGregory Neil Shapiro 	bool trycanon = false;
55040266059SGregory Neil Shapiro 	unsigned short *prefs;
551b6bacd31SGregory Neil Shapiro 	int (*resfunc) __P((const char *, int, int, u_char *, int));
55240266059SGregory Neil Shapiro 	unsigned short prefer[MAXMXHOSTS];
553c2aa98e2SPeter Wemm 	int weight[MAXMXHOSTS];
55440266059SGregory Neil Shapiro 	int ttl = 0;
555*5b0945b5SGregory Neil Shapiro 	bool ad;
556*5b0945b5SGregory Neil Shapiro 	bool seennullmx = false;
55706f25ae9SGregory Neil Shapiro 	extern int res_query(), res_search();
558*5b0945b5SGregory Neil Shapiro # if DANE
559*5b0945b5SGregory Neil Shapiro 	bool cname2mx;
560*5b0945b5SGregory Neil Shapiro 	char qname[MAXNAME];
561*5b0945b5SGregory Neil Shapiro 	unsigned long old_options = 0;
562*5b0945b5SGregory Neil Shapiro # endif
563c2aa98e2SPeter Wemm 
564c2aa98e2SPeter Wemm 	if (tTd(8, 2))
565*5b0945b5SGregory Neil Shapiro 		sm_dprintf("getmxrr(%s, droplocalhost=%d, flags=%X, port=%d)\n",
566*5b0945b5SGregory Neil Shapiro 			   host, (flags & DROPLOCALHOST) != 0, flags, port);
567*5b0945b5SGregory Neil Shapiro 	ad = (flags & ISAD) != 0;
56813d88268SGregory Neil Shapiro 	*rcode = EX_OK;
56913d88268SGregory Neil Shapiro 	if (pttl != NULL)
57013d88268SGregory Neil Shapiro 		*pttl = SM_DEFAULT_TTL;
571a7ec597cSGregory Neil Shapiro 	if (*host == '\0')
572a7ec597cSGregory Neil Shapiro 		return 0;
573*5b0945b5SGregory Neil Shapiro # if DANE
574*5b0945b5SGregory Neil Shapiro 	cname2mx = false;
575*5b0945b5SGregory Neil Shapiro 	qname[0] = '\0';
576*5b0945b5SGregory Neil Shapiro 	old_options = _res.options;
577*5b0945b5SGregory Neil Shapiro 	if (ad)
578*5b0945b5SGregory Neil Shapiro 		_res.options |= SM_RES_DNSSEC;
579*5b0945b5SGregory Neil Shapiro # endif
580c2aa98e2SPeter Wemm 
581*5b0945b5SGregory Neil Shapiro 	if ((fallbackMX != NULL && (flags & DROPLOCALHOST) != 0 &&
582*5b0945b5SGregory Neil Shapiro 	     wordinclass(fallbackMX, 'w')) || (flags & TRYFALLBACK) == 0)
583c2aa98e2SPeter Wemm 	{
584c2aa98e2SPeter Wemm 		/* don't use fallback for this pass */
585c2aa98e2SPeter Wemm 		fallbackMX = NULL;
586c2aa98e2SPeter Wemm 	}
587c2aa98e2SPeter Wemm 
58806f25ae9SGregory Neil Shapiro 	if (mxprefs != NULL)
58906f25ae9SGregory Neil Shapiro 		prefs = mxprefs;
59006f25ae9SGregory Neil Shapiro 	else
59106f25ae9SGregory Neil Shapiro 		prefs = prefer;
59206f25ae9SGregory Neil Shapiro 
593c2aa98e2SPeter Wemm 	/* efficiency hack -- numeric or non-MX lookups */
594c2aa98e2SPeter Wemm 	if (host[0] == '[')
595c2aa98e2SPeter Wemm 		goto punt;
596c2aa98e2SPeter Wemm 
597*5b0945b5SGregory Neil Shapiro # if DANE
598*5b0945b5SGregory Neil Shapiro 	/*
599*5b0945b5SGregory Neil Shapiro 	**  NOTE: This only works if nocanonify is used,
600*5b0945b5SGregory Neil Shapiro 	**  otherwise the name is already rewritten.
601*5b0945b5SGregory Neil Shapiro 	*/
602*5b0945b5SGregory Neil Shapiro 
603*5b0945b5SGregory Neil Shapiro 	/* always or only when "needed"? */
604*5b0945b5SGregory Neil Shapiro 	if (DANE_ALWAYS == Dane || (ad && DANE_SECURE == Dane))
605*5b0945b5SGregory Neil Shapiro 		(void) sm_strlcpy(qname, host, sizeof(qname));
606*5b0945b5SGregory Neil Shapiro # endif /* DANE */
607*5b0945b5SGregory Neil Shapiro 
608*5b0945b5SGregory Neil Shapiro # if _FFR_EAI
609*5b0945b5SGregory Neil Shapiro 	if (!addr_is_ascii(host))
610*5b0945b5SGregory Neil Shapiro 	{
611*5b0945b5SGregory Neil Shapiro 		char buf[1024];
612*5b0945b5SGregory Neil Shapiro 		UErrorCode error = U_ZERO_ERROR;
613*5b0945b5SGregory Neil Shapiro 		UIDNAInfo info = UIDNA_INFO_INITIALIZER;
614*5b0945b5SGregory Neil Shapiro 		UIDNA *idna;
615*5b0945b5SGregory Neil Shapiro 
616*5b0945b5SGregory Neil Shapiro 		idna = uidna_openUTS46(UIDNA_NONTRANSITIONAL_TO_ASCII, &error);
617*5b0945b5SGregory Neil Shapiro 		(void) uidna_nameToASCII_UTF8(idna, host, strlen(host),
618*5b0945b5SGregory Neil Shapiro 					     buf, sizeof(buf) - 1,
619*5b0945b5SGregory Neil Shapiro 					     &info, &error);
620*5b0945b5SGregory Neil Shapiro 		uidna_close(idna);
621*5b0945b5SGregory Neil Shapiro 		host = sm_rpool_strdup_x(CurEnv->e_rpool, buf);
622*5b0945b5SGregory Neil Shapiro 	}
623*5b0945b5SGregory Neil Shapiro # endif /* _FFR_EAI */
624*5b0945b5SGregory Neil Shapiro 
625c2aa98e2SPeter Wemm 	/*
626c2aa98e2SPeter Wemm 	**  If we don't have MX records in our host switch, don't
627c2aa98e2SPeter Wemm 	**  try for MX records.  Note that this really isn't "right",
628c2aa98e2SPeter Wemm 	**  since we might be set up to try NIS first and then DNS;
629c2aa98e2SPeter Wemm 	**  if the host is found in NIS we really shouldn't be doing
630c2aa98e2SPeter Wemm 	**  MX lookups.  However, that should be a degenerate case.
631c2aa98e2SPeter Wemm 	*/
632c2aa98e2SPeter Wemm 
633c2aa98e2SPeter Wemm 	if (!UseNameServer)
634c2aa98e2SPeter Wemm 		goto punt;
635c2aa98e2SPeter Wemm 	if (HasWildcardMX && ConfigLevel >= 6)
636c2aa98e2SPeter Wemm 		resfunc = res_query;
637c2aa98e2SPeter Wemm 	else
638c2aa98e2SPeter Wemm 		resfunc = res_search;
639*5b0945b5SGregory Neil Shapiro # if DNSSEC_TEST
640*5b0945b5SGregory Neil Shapiro 	if (tTd(8, 110))
641*5b0945b5SGregory Neil Shapiro 		resfunc = tstdns_search;
642*5b0945b5SGregory Neil Shapiro # endif
643c2aa98e2SPeter Wemm 
644c2aa98e2SPeter Wemm 	errno = 0;
645*5b0945b5SGregory Neil Shapiro 	hp = (HEADER *)&answer;
64640266059SGregory Neil Shapiro 	n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer,
64740266059SGregory Neil Shapiro 		       sizeof(answer));
648c2aa98e2SPeter Wemm 	if (n < 0)
649c2aa98e2SPeter Wemm 	{
650c2aa98e2SPeter Wemm 		if (tTd(8, 1))
651*5b0945b5SGregory Neil Shapiro # if DNSSEC_TEST
652*5b0945b5SGregory Neil Shapiro 			sm_dprintf("getmxrr: res_search(%s) failed (errno=%d (%s), h_errno=%d (%s))\n",
653*5b0945b5SGregory Neil Shapiro 				host, errno, strerror(errno),
654*5b0945b5SGregory Neil Shapiro 				h_errno, herrno2txt(h_errno));
655*5b0945b5SGregory Neil Shapiro # else
656*5b0945b5SGregory Neil Shapiro 			sm_dprintf("getmxrr: res_search(%s) failed, h_errno=%d\n",
657*5b0945b5SGregory Neil Shapiro 				host, h_errno);
658*5b0945b5SGregory Neil Shapiro # endif
659c2aa98e2SPeter Wemm 		switch (h_errno)
660c2aa98e2SPeter Wemm 		{
661c2aa98e2SPeter Wemm 		  case NO_DATA:
66240266059SGregory Neil Shapiro 			trycanon = true;
66306f25ae9SGregory Neil Shapiro 			/* FALLTHROUGH */
664c2aa98e2SPeter Wemm 
665c2aa98e2SPeter Wemm 		  case NO_RECOVERY:
666c2aa98e2SPeter Wemm 			/* no MX data on this host */
667c2aa98e2SPeter Wemm 			goto punt;
668c2aa98e2SPeter Wemm 
669c2aa98e2SPeter Wemm 		  case HOST_NOT_FOUND:
670c2aa98e2SPeter Wemm # if BROKEN_RES_SEARCH
671*5b0945b5SGregory Neil Shapiro 		  case 0: /* Ultrix resolver returns failure w/ h_errno=0 */
672*5b0945b5SGregory Neil Shapiro # endif
673c2aa98e2SPeter Wemm 			/* host doesn't exist in DNS; might be in /etc/hosts */
67440266059SGregory Neil Shapiro 			trycanon = true;
675c2aa98e2SPeter Wemm 			*rcode = EX_NOHOST;
676c2aa98e2SPeter Wemm 			goto punt;
677c2aa98e2SPeter Wemm 
678c2aa98e2SPeter Wemm 		  case TRY_AGAIN:
679c2aa98e2SPeter Wemm 		  case -1:
680c2aa98e2SPeter Wemm 			/* couldn't connect to the name server */
681c2aa98e2SPeter Wemm 			if (fallbackMX != NULL)
682c2aa98e2SPeter Wemm 			{
683c2aa98e2SPeter Wemm 				/* name server is hosed -- push to fallback */
684*5b0945b5SGregory Neil Shapiro 				nmx = fallbackmxrr(nmx, prefs, mxhosts);
685*5b0945b5SGregory Neil Shapiro 				goto done;
686c2aa98e2SPeter Wemm 			}
687c2aa98e2SPeter Wemm 			/* it might come up later; better queue it up */
688c2aa98e2SPeter Wemm 			*rcode = EX_TEMPFAIL;
689c2aa98e2SPeter Wemm 			break;
690c2aa98e2SPeter Wemm 
691c2aa98e2SPeter Wemm 		  default:
69240266059SGregory Neil Shapiro 			syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)",
693c2aa98e2SPeter Wemm 				host, h_errno);
694c2aa98e2SPeter Wemm 			*rcode = EX_OSERR;
695c2aa98e2SPeter Wemm 			break;
696c2aa98e2SPeter Wemm 		}
697c2aa98e2SPeter Wemm 
698c2aa98e2SPeter Wemm 		/* irreconcilable differences */
699*5b0945b5SGregory Neil Shapiro 		goto error;
700c2aa98e2SPeter Wemm 	}
701c2aa98e2SPeter Wemm 
702*5b0945b5SGregory Neil Shapiro 	ad = ad && hp->ad;
703*5b0945b5SGregory Neil Shapiro 	if (tTd(8, 2))
704*5b0945b5SGregory Neil Shapiro 		sm_dprintf("getmxrr(%s), hp=%p, ad=%d\n", host, (void*)hp, ad);
705*5b0945b5SGregory Neil Shapiro 
706c2aa98e2SPeter Wemm 	/* avoid problems after truncation in tcp packets */
707c2aa98e2SPeter Wemm 	if (n > sizeof(answer))
708c2aa98e2SPeter Wemm 		n = sizeof(answer);
709c2aa98e2SPeter Wemm 
710c2aa98e2SPeter Wemm 	/* find first satisfactory answer */
71140266059SGregory Neil Shapiro 	cp = (unsigned char *)&answer + HFIXEDSZ;
71240266059SGregory Neil Shapiro 	eom = (unsigned char *)&answer + n;
713*5b0945b5SGregory Neil Shapiro 
71440266059SGregory Neil Shapiro 	for (qdcount = ntohs((unsigned short) hp->qdcount);
71506f25ae9SGregory Neil Shapiro 	     qdcount--;
71606f25ae9SGregory Neil Shapiro 	     cp += n + QFIXEDSZ)
71706f25ae9SGregory Neil Shapiro 	{
718c2aa98e2SPeter Wemm 		if ((n = dn_skipname(cp, eom)) < 0)
719c2aa98e2SPeter Wemm 			goto punt;
72006f25ae9SGregory Neil Shapiro 	}
72140266059SGregory Neil Shapiro 
72240266059SGregory Neil Shapiro 	/* NOTE: see definition of MXHostBuf! */
723c2aa98e2SPeter Wemm 	buflen = sizeof(MXHostBuf) - 1;
72440266059SGregory Neil Shapiro 	SM_ASSERT(buflen > 0);
725c2aa98e2SPeter Wemm 	bp = MXHostBuf;
72640266059SGregory Neil Shapiro 	ancount = ntohs((unsigned short) hp->ancount);
72740266059SGregory Neil Shapiro 
72840266059SGregory Neil Shapiro 	/* See RFC 1035 for layout of RRs. */
729e92d3f3fSGregory Neil Shapiro 	/* XXX leave room for FallbackMX ? */
730c2aa98e2SPeter Wemm 	while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
731c2aa98e2SPeter Wemm 	{
73240266059SGregory Neil Shapiro 		if ((n = dn_expand((unsigned char *)&answer, eom, cp,
73340266059SGregory Neil Shapiro 				   (RES_UNC_T) bp, buflen)) < 0)
734c2aa98e2SPeter Wemm 			break;
735c2aa98e2SPeter Wemm 		cp += n;
736c2aa98e2SPeter Wemm 		GETSHORT(type, cp);
73740266059SGregory Neil Shapiro 		cp += INT16SZ;		/* skip over class */
73840266059SGregory Neil Shapiro 		GETLONG(ttl, cp);
73940266059SGregory Neil Shapiro 		GETSHORT(n, cp);	/* rdlength */
740*5b0945b5SGregory Neil Shapiro # if DANE
741*5b0945b5SGregory Neil Shapiro 		if (type == T_CNAME)
742*5b0945b5SGregory Neil Shapiro 			cname2mx = true;
743*5b0945b5SGregory Neil Shapiro # endif
744c2aa98e2SPeter Wemm 		if (type != T_MX)
745c2aa98e2SPeter Wemm 		{
746*5b0945b5SGregory Neil Shapiro 			if ((tTd(8, 8) || _res.options & RES_DEBUG)
747*5b0945b5SGregory Neil Shapiro # if DANE
748*5b0945b5SGregory Neil Shapiro 			    && type != T_RRSIG
749*5b0945b5SGregory Neil Shapiro # endif
750*5b0945b5SGregory Neil Shapiro 			    )
751*5b0945b5SGregory Neil Shapiro 				sm_dprintf("unexpected answer type %s, size %d\n",
752*5b0945b5SGregory Neil Shapiro 					dns_type_to_string(type), n);
753c2aa98e2SPeter Wemm 			cp += n;
754c2aa98e2SPeter Wemm 			continue;
755c2aa98e2SPeter Wemm 		}
756c2aa98e2SPeter Wemm 		GETSHORT(pref, cp);
75740266059SGregory Neil Shapiro 		if ((n = dn_expand((unsigned char *)&answer, eom, cp,
758c2aa98e2SPeter Wemm 				   (RES_UNC_T) bp, buflen)) < 0)
759c2aa98e2SPeter Wemm 			break;
760c2aa98e2SPeter Wemm 		cp += n;
76140266059SGregory Neil Shapiro 		n = strlen(bp);
762*5b0945b5SGregory Neil Shapiro 
763*5b0945b5SGregory Neil Shapiro 		/* Support for RFC7505 "MX 0 ." */
764*5b0945b5SGregory Neil Shapiro 		if (pref == 0 && *bp == '\0')
765*5b0945b5SGregory Neil Shapiro 			seennullmx = true;
766*5b0945b5SGregory Neil Shapiro 
767c2aa98e2SPeter Wemm 		if (wordinclass(bp, 'w'))
768c2aa98e2SPeter Wemm 		{
769c2aa98e2SPeter Wemm 			if (tTd(8, 3))
77040266059SGregory Neil Shapiro 				sm_dprintf("found localhost (%s) in MX list, pref=%d\n",
771c2aa98e2SPeter Wemm 					bp, pref);
772*5b0945b5SGregory Neil Shapiro 			if ((flags & DROPLOCALHOST) != 0)
773c2aa98e2SPeter Wemm 			{
774c2aa98e2SPeter Wemm 				if (!seenlocal || pref < localpref)
775c2aa98e2SPeter Wemm 					localpref = pref;
77640266059SGregory Neil Shapiro 				seenlocal = true;
777c2aa98e2SPeter Wemm 				continue;
778c2aa98e2SPeter Wemm 			}
779c2aa98e2SPeter Wemm 			weight[nmx] = 0;
780c2aa98e2SPeter Wemm 		}
781c2aa98e2SPeter Wemm 		else
782c2aa98e2SPeter Wemm 			weight[nmx] = mxrand(bp);
78306f25ae9SGregory Neil Shapiro 		prefs[nmx] = pref;
784c2aa98e2SPeter Wemm 		mxhosts[nmx++] = bp;
785*5b0945b5SGregory Neil Shapiro # if DANE
786*5b0945b5SGregory Neil Shapiro 		if (CHK_DANE(Dane) && port >= 0)
787*5b0945b5SGregory Neil Shapiro 		{
788*5b0945b5SGregory Neil Shapiro 			int nrr;
789*5b0945b5SGregory Neil Shapiro 			unsigned long flags;
790*5b0945b5SGregory Neil Shapiro 
791*5b0945b5SGregory Neil Shapiro 			flags = ad ? TLSAFLADMX : TLSAFLNOADMX;
792*5b0945b5SGregory Neil Shapiro 			nrr = gettlsa(bp, NULL, NULL, flags, ttl, port);
793*5b0945b5SGregory Neil Shapiro 
794*5b0945b5SGregory Neil Shapiro 			/* Only check qname if no TLSA RRs were found */
795*5b0945b5SGregory Neil Shapiro 			if (0 == nrr && cname2mx && '\0' != qname[0] &&
796*5b0945b5SGregory Neil Shapiro 			    strcmp(qname, bp))
797*5b0945b5SGregory Neil Shapiro 				gettlsa(qname, bp, NULL, flags, ttl, port);
798*5b0945b5SGregory Neil Shapiro 			/* XXX is this the right ad flag? */
799*5b0945b5SGregory Neil Shapiro 		}
800*5b0945b5SGregory Neil Shapiro # endif
801*5b0945b5SGregory Neil Shapiro 
802*5b0945b5SGregory Neil Shapiro 		/*
803*5b0945b5SGregory Neil Shapiro 		**  Note: n can be 0 for something like:
804*5b0945b5SGregory Neil Shapiro 		**  host MX 0 .
805*5b0945b5SGregory Neil Shapiro 		**  See RFC 7505
806*5b0945b5SGregory Neil Shapiro 		*/
807*5b0945b5SGregory Neil Shapiro 
808c2aa98e2SPeter Wemm 		bp += n;
809*5b0945b5SGregory Neil Shapiro 		if (0 == n || bp[-1] != '.')
810c2aa98e2SPeter Wemm 		{
811c2aa98e2SPeter Wemm 			*bp++ = '.';
812c2aa98e2SPeter Wemm 			n++;
813c2aa98e2SPeter Wemm 		}
814c2aa98e2SPeter Wemm 		*bp++ = '\0';
81540266059SGregory Neil Shapiro 		if (buflen < n + 1)
81640266059SGregory Neil Shapiro 		{
81740266059SGregory Neil Shapiro 			/* don't want to wrap buflen */
81840266059SGregory Neil Shapiro 			break;
81940266059SGregory Neil Shapiro 		}
820c2aa98e2SPeter Wemm 		buflen -= n + 1;
821c2aa98e2SPeter Wemm 	}
822c2aa98e2SPeter Wemm 
823*5b0945b5SGregory Neil Shapiro 	/* Support for RFC7505 "MX 0 ." */
824*5b0945b5SGregory Neil Shapiro 	if (seennullmx && nmx == 1)
825*5b0945b5SGregory Neil Shapiro 	{
826*5b0945b5SGregory Neil Shapiro 		if (tTd(8, 4))
827*5b0945b5SGregory Neil Shapiro 			sm_dprintf("getmxrr: Null MX record found, domain doesn't accept mail (RFC7505)\n");
828*5b0945b5SGregory Neil Shapiro 		*rcode = EX_UNAVAILABLE;
829*5b0945b5SGregory Neil Shapiro 		return NULLMX;
830*5b0945b5SGregory Neil Shapiro 	}
831*5b0945b5SGregory Neil Shapiro 
83240266059SGregory Neil Shapiro 	/* return only one TTL entry, that should be sufficient */
83340266059SGregory Neil Shapiro 	if (ttl > 0 && pttl != NULL)
83440266059SGregory Neil Shapiro 		*pttl = ttl;
83540266059SGregory Neil Shapiro 
836c2aa98e2SPeter Wemm 	/* sort the records */
837c2aa98e2SPeter Wemm 	for (i = 0; i < nmx; i++)
838c2aa98e2SPeter Wemm 	{
839c2aa98e2SPeter Wemm 		for (j = i + 1; j < nmx; j++)
840c2aa98e2SPeter Wemm 		{
84106f25ae9SGregory Neil Shapiro 			if (prefs[i] > prefs[j] ||
84206f25ae9SGregory Neil Shapiro 			    (prefs[i] == prefs[j] && weight[i] > weight[j]))
843c2aa98e2SPeter Wemm 			{
844c2aa98e2SPeter Wemm 				register int temp;
845c2aa98e2SPeter Wemm 				register char *temp1;
846c2aa98e2SPeter Wemm 
84706f25ae9SGregory Neil Shapiro 				temp = prefs[i];
84806f25ae9SGregory Neil Shapiro 				prefs[i] = prefs[j];
84906f25ae9SGregory Neil Shapiro 				prefs[j] = temp;
850c2aa98e2SPeter Wemm 				temp1 = mxhosts[i];
851c2aa98e2SPeter Wemm 				mxhosts[i] = mxhosts[j];
852c2aa98e2SPeter Wemm 				mxhosts[j] = temp1;
853c2aa98e2SPeter Wemm 				temp = weight[i];
854c2aa98e2SPeter Wemm 				weight[i] = weight[j];
855c2aa98e2SPeter Wemm 				weight[j] = temp;
856c2aa98e2SPeter Wemm 			}
857c2aa98e2SPeter Wemm 		}
85806f25ae9SGregory Neil Shapiro 		if (seenlocal && prefs[i] >= localpref)
859c2aa98e2SPeter Wemm 		{
860c2aa98e2SPeter Wemm 			/* truncate higher preference part of list */
861c2aa98e2SPeter Wemm 			nmx = i;
862c2aa98e2SPeter Wemm 		}
863c2aa98e2SPeter Wemm 	}
864c2aa98e2SPeter Wemm 
865c2aa98e2SPeter Wemm 	/* delete duplicates from list (yes, some bozos have duplicates) */
866c2aa98e2SPeter Wemm 	for (i = 0; i < nmx - 1; )
867c2aa98e2SPeter Wemm 	{
86840266059SGregory Neil Shapiro 		if (sm_strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0)
869c2aa98e2SPeter Wemm 			i++;
870c2aa98e2SPeter Wemm 		else
871c2aa98e2SPeter Wemm 		{
872c2aa98e2SPeter Wemm 			/* compress out duplicate */
873c2aa98e2SPeter Wemm 			for (j = i + 1; j < nmx; j++)
87406f25ae9SGregory Neil Shapiro 			{
875c2aa98e2SPeter Wemm 				mxhosts[j] = mxhosts[j + 1];
87606f25ae9SGregory Neil Shapiro 				prefs[j] = prefs[j + 1];
87706f25ae9SGregory Neil Shapiro 			}
878c2aa98e2SPeter Wemm 			nmx--;
879c2aa98e2SPeter Wemm 		}
880c2aa98e2SPeter Wemm 	}
881c2aa98e2SPeter Wemm 
882c2aa98e2SPeter Wemm 	if (nmx == 0)
883c2aa98e2SPeter Wemm 	{
884c2aa98e2SPeter Wemm punt:
88506f25ae9SGregory Neil Shapiro 		if (seenlocal)
886c2aa98e2SPeter Wemm 		{
88706f25ae9SGregory Neil Shapiro 			struct hostent *h = NULL;
88806f25ae9SGregory Neil Shapiro 
889c2aa98e2SPeter Wemm 			/*
890c2aa98e2SPeter Wemm 			**  If we have deleted all MX entries, this is
891c2aa98e2SPeter Wemm 			**  an error -- we should NEVER send to a host that
892c2aa98e2SPeter Wemm 			**  has an MX, and this should have been caught
893c2aa98e2SPeter Wemm 			**  earlier in the config file.
894c2aa98e2SPeter Wemm 			**
895c2aa98e2SPeter Wemm 			**  Some sites prefer to go ahead and try the
896c2aa98e2SPeter Wemm 			**  A record anyway; that case is handled by
897c2aa98e2SPeter Wemm 			**  setting TryNullMXList.  I believe this is a
898c2aa98e2SPeter Wemm 			**  bad idea, but it's up to you....
899c2aa98e2SPeter Wemm 			*/
900c2aa98e2SPeter Wemm 
90106f25ae9SGregory Neil Shapiro 			if (TryNullMXList)
90206f25ae9SGregory Neil Shapiro 			{
903602a2b1bSGregory Neil Shapiro 				SM_SET_H_ERRNO(0);
90406f25ae9SGregory Neil Shapiro 				errno = 0;
90506f25ae9SGregory Neil Shapiro 				h = sm_gethostbyname(host, AF_INET);
90606f25ae9SGregory Neil Shapiro 				if (h == NULL)
90706f25ae9SGregory Neil Shapiro 				{
90806f25ae9SGregory Neil Shapiro 					if (errno == ETIMEDOUT ||
90906f25ae9SGregory Neil Shapiro 					    h_errno == TRY_AGAIN ||
91006f25ae9SGregory Neil Shapiro 					    (errno == ECONNREFUSED &&
91106f25ae9SGregory Neil Shapiro 					     UseNameServer))
91206f25ae9SGregory Neil Shapiro 					{
91306f25ae9SGregory Neil Shapiro 						*rcode = EX_TEMPFAIL;
914*5b0945b5SGregory Neil Shapiro 						goto error;
91506f25ae9SGregory Neil Shapiro 					}
91606f25ae9SGregory Neil Shapiro # if NETINET6
917602a2b1bSGregory Neil Shapiro 					SM_SET_H_ERRNO(0);
91806f25ae9SGregory Neil Shapiro 					errno = 0;
91906f25ae9SGregory Neil Shapiro 					h = sm_gethostbyname(host, AF_INET6);
92006f25ae9SGregory Neil Shapiro 					if (h == NULL &&
92106f25ae9SGregory Neil Shapiro 					    (errno == ETIMEDOUT ||
92206f25ae9SGregory Neil Shapiro 					     h_errno == TRY_AGAIN ||
92306f25ae9SGregory Neil Shapiro 					     (errno == ECONNREFUSED &&
92406f25ae9SGregory Neil Shapiro 					      UseNameServer)))
92506f25ae9SGregory Neil Shapiro 					{
92606f25ae9SGregory Neil Shapiro 						*rcode = EX_TEMPFAIL;
927*5b0945b5SGregory Neil Shapiro 						goto error;
92806f25ae9SGregory Neil Shapiro 					}
92906f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
93006f25ae9SGregory Neil Shapiro 				}
93106f25ae9SGregory Neil Shapiro 			}
93206f25ae9SGregory Neil Shapiro 
93306f25ae9SGregory Neil Shapiro 			if (h == NULL)
93406f25ae9SGregory Neil Shapiro 			{
935c2aa98e2SPeter Wemm 				*rcode = EX_CONFIG;
936c2aa98e2SPeter Wemm 				syserr("MX list for %s points back to %s",
937c2aa98e2SPeter Wemm 				       host, MyHostName);
938*5b0945b5SGregory Neil Shapiro 				goto error;
939c2aa98e2SPeter Wemm 			}
94040266059SGregory Neil Shapiro # if NETINET6
941193538b7SGregory Neil Shapiro 			freehostent(h);
942af9557fdSGregory Neil Shapiro 			h = NULL;
943*5b0945b5SGregory Neil Shapiro # endif
94406f25ae9SGregory Neil Shapiro 		}
945d0cef73dSGregory Neil Shapiro 		if (strlen(host) >= sizeof(MXHostBuf))
946c2aa98e2SPeter Wemm 		{
947c2aa98e2SPeter Wemm 			*rcode = EX_CONFIG;
948c2aa98e2SPeter Wemm 			syserr("Host name %s too long",
949c2aa98e2SPeter Wemm 			       shortenstring(host, MAXSHORTSTR));
950*5b0945b5SGregory Neil Shapiro 			goto error;
951c2aa98e2SPeter Wemm 		}
952d0cef73dSGregory Neil Shapiro 		(void) sm_strlcpy(MXHostBuf, host, sizeof(MXHostBuf));
953c2aa98e2SPeter Wemm 		mxhosts[0] = MXHostBuf;
95406f25ae9SGregory Neil Shapiro 		prefs[0] = 0;
955c2aa98e2SPeter Wemm 		if (host[0] == '[')
956c2aa98e2SPeter Wemm 		{
957c2aa98e2SPeter Wemm 			register char *p;
95806f25ae9SGregory Neil Shapiro # if NETINET6
95906f25ae9SGregory Neil Shapiro 			struct sockaddr_in6 tmp6;
960*5b0945b5SGregory Neil Shapiro # endif
961c2aa98e2SPeter Wemm 
962c2aa98e2SPeter Wemm 			/* this may be an MX suppression-style address */
963c2aa98e2SPeter Wemm 			p = strchr(MXHostBuf, ']');
964c2aa98e2SPeter Wemm 			if (p != NULL)
965c2aa98e2SPeter Wemm 			{
966c2aa98e2SPeter Wemm 				*p = '\0';
96706f25ae9SGregory Neil Shapiro 
968c2aa98e2SPeter Wemm 				if (inet_addr(&MXHostBuf[1]) != INADDR_NONE)
969c2aa98e2SPeter Wemm 				{
970c2aa98e2SPeter Wemm 					nmx++;
971c2aa98e2SPeter Wemm 					*p = ']';
972c2aa98e2SPeter Wemm 				}
97306f25ae9SGregory Neil Shapiro # if NETINET6
97440266059SGregory Neil Shapiro 				else if (anynet_pton(AF_INET6, &MXHostBuf[1],
97506f25ae9SGregory Neil Shapiro 						     &tmp6.sin6_addr) == 1)
97606f25ae9SGregory Neil Shapiro 				{
97706f25ae9SGregory Neil Shapiro 					nmx++;
97806f25ae9SGregory Neil Shapiro 					*p = ']';
97906f25ae9SGregory Neil Shapiro 				}
98006f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
981c2aa98e2SPeter Wemm 				else
982c2aa98e2SPeter Wemm 				{
98340266059SGregory Neil Shapiro 					trycanon = true;
984c2aa98e2SPeter Wemm 					mxhosts[0]++;
985c2aa98e2SPeter Wemm 				}
986c2aa98e2SPeter Wemm 			}
987c2aa98e2SPeter Wemm 		}
988c2aa98e2SPeter Wemm 		if (trycanon &&
989*5b0945b5SGregory Neil Shapiro 		    (n = getcanonname(mxhosts[0], sizeof(MXHostBuf) - 2, false,
990*5b0945b5SGregory Neil Shapiro 				pttl)) != HOST_NOTFOUND)
991c2aa98e2SPeter Wemm 		{
99240266059SGregory Neil Shapiro 			/* XXX MXHostBuf == "" ?  is that possible? */
993c2aa98e2SPeter Wemm 			bp = &MXHostBuf[strlen(MXHostBuf)];
994c2aa98e2SPeter Wemm 			if (bp[-1] != '.')
995c2aa98e2SPeter Wemm 			{
996c2aa98e2SPeter Wemm 				*bp++ = '.';
997c2aa98e2SPeter Wemm 				*bp = '\0';
998c2aa98e2SPeter Wemm 			}
999c2aa98e2SPeter Wemm 			nmx = 1;
1000*5b0945b5SGregory Neil Shapiro # if DANE
1001*5b0945b5SGregory Neil Shapiro 			if (tTd(8, 3))
1002*5b0945b5SGregory Neil Shapiro 				sm_dprintf("getmxrr=%s, getcanonname=%d\n",
1003*5b0945b5SGregory Neil Shapiro 					mxhosts[0], n);
1004*5b0945b5SGregory Neil Shapiro 			if (CHK_DANE(Dane) && port >= 0)
1005*5b0945b5SGregory Neil Shapiro 			{
1006*5b0945b5SGregory Neil Shapiro 				int nrr;
1007*5b0945b5SGregory Neil Shapiro 				unsigned long flags;
1008*5b0945b5SGregory Neil Shapiro 				unsigned int cttl;
1009*5b0945b5SGregory Neil Shapiro 
1010*5b0945b5SGregory Neil Shapiro 				if (pttl != NULL)
1011*5b0945b5SGregory Neil Shapiro 					cttl = *pttl;
1012*5b0945b5SGregory Neil Shapiro 				else if (ttl > 0)
1013*5b0945b5SGregory Neil Shapiro 					cttl = ttl;
1014*5b0945b5SGregory Neil Shapiro 				else
1015*5b0945b5SGregory Neil Shapiro 					cttl = SM_DEFAULT_TTL;
1016*5b0945b5SGregory Neil Shapiro 
1017*5b0945b5SGregory Neil Shapiro 				flags = (ad && n == HOST_SECURE)
1018*5b0945b5SGregory Neil Shapiro 					? TLSAFLADMX : TLSAFLNOADMX;
1019*5b0945b5SGregory Neil Shapiro 				nrr = gettlsa(mxhosts[0], NULL, NULL, flags,
1020*5b0945b5SGregory Neil Shapiro 						cttl, port);
1021*5b0945b5SGregory Neil Shapiro 
1022*5b0945b5SGregory Neil Shapiro 				/*
1023*5b0945b5SGregory Neil Shapiro 				**  Only check qname if no TLSA RRs were found
1024*5b0945b5SGregory Neil Shapiro 				**  XXX: what about (temp) DNS errors?
1025*5b0945b5SGregory Neil Shapiro 				*/
1026*5b0945b5SGregory Neil Shapiro 
1027*5b0945b5SGregory Neil Shapiro 				if (0 == nrr && '\0' != qname[0] &&
1028*5b0945b5SGregory Neil Shapiro 				    strcmp(qname, mxhosts[0]))
1029*5b0945b5SGregory Neil Shapiro 					gettlsa(qname, mxhosts[0], NULL, flags,
1030*5b0945b5SGregory Neil Shapiro 						cttl, port);
1031*5b0945b5SGregory Neil Shapiro 				/* XXX is this the right ad flag? */
1032*5b0945b5SGregory Neil Shapiro 			}
1033*5b0945b5SGregory Neil Shapiro # endif
1034c2aa98e2SPeter Wemm 		}
1035c2aa98e2SPeter Wemm 	}
1036c2aa98e2SPeter Wemm 
1037c2aa98e2SPeter Wemm 	/* if we have a default lowest preference, include that */
1038c2aa98e2SPeter Wemm 	if (fallbackMX != NULL && !seenlocal)
103906f25ae9SGregory Neil Shapiro 	{
1040*5b0945b5SGregory Neil Shapiro 		/* TODO: DNSsec status of fallbacks */
104140266059SGregory Neil Shapiro 		nmx = fallbackmxrr(nmx, prefs, mxhosts);
104206f25ae9SGregory Neil Shapiro 	}
1043*5b0945b5SGregory Neil Shapiro     done:
1044*5b0945b5SGregory Neil Shapiro # if DANE
1045*5b0945b5SGregory Neil Shapiro 	_res.options = old_options;
1046*5b0945b5SGregory Neil Shapiro # endif
104706f25ae9SGregory Neil Shapiro 	return nmx;
1048*5b0945b5SGregory Neil Shapiro 
1049*5b0945b5SGregory Neil Shapiro    error:
1050*5b0945b5SGregory Neil Shapiro # if DANE
1051*5b0945b5SGregory Neil Shapiro 	_res.options = old_options;
1052*5b0945b5SGregory Neil Shapiro # endif
1053*5b0945b5SGregory Neil Shapiro 	return -1;
1054c2aa98e2SPeter Wemm }
1055*5b0945b5SGregory Neil Shapiro 
105640266059SGregory Neil Shapiro /*
1057c2aa98e2SPeter Wemm **  MXRAND -- create a randomizer for equal MX preferences
1058c2aa98e2SPeter Wemm **
1059c2aa98e2SPeter Wemm **	If two MX hosts have equal preferences we want to randomize
1060c2aa98e2SPeter Wemm **	the selection.  But in order for signatures to be the same,
1061c2aa98e2SPeter Wemm **	we need to randomize the same way each time.  This function
1062c2aa98e2SPeter Wemm **	computes a pseudo-random hash function from the host name.
1063c2aa98e2SPeter Wemm **
1064c2aa98e2SPeter Wemm **	Parameters:
1065c2aa98e2SPeter Wemm **		host -- the name of the host.
1066c2aa98e2SPeter Wemm **
1067c2aa98e2SPeter Wemm **	Returns:
1068c2aa98e2SPeter Wemm **		A random but repeatable value based on the host name.
1069c2aa98e2SPeter Wemm */
1070c2aa98e2SPeter Wemm 
107106f25ae9SGregory Neil Shapiro static int
1072c2aa98e2SPeter Wemm mxrand(host)
1073c2aa98e2SPeter Wemm 	register char *host;
1074c2aa98e2SPeter Wemm {
1075c2aa98e2SPeter Wemm 	int hfunc;
1076c2aa98e2SPeter Wemm 	static unsigned int seed;
1077c2aa98e2SPeter Wemm 
1078c2aa98e2SPeter Wemm 	if (seed == 0)
1079c2aa98e2SPeter Wemm 	{
1080c2aa98e2SPeter Wemm 		seed = (int) curtime() & 0xffff;
1081c2aa98e2SPeter Wemm 		if (seed == 0)
1082c2aa98e2SPeter Wemm 			seed++;
1083c2aa98e2SPeter Wemm 	}
1084c2aa98e2SPeter Wemm 
1085c2aa98e2SPeter Wemm 	if (tTd(17, 9))
108640266059SGregory Neil Shapiro 		sm_dprintf("mxrand(%s)", host);
1087c2aa98e2SPeter Wemm 
1088c2aa98e2SPeter Wemm 	hfunc = seed;
1089c2aa98e2SPeter Wemm 	while (*host != '\0')
1090c2aa98e2SPeter Wemm 	{
1091c2aa98e2SPeter Wemm 		int c = *host++;
1092c2aa98e2SPeter Wemm 
1093c2aa98e2SPeter Wemm 		if (isascii(c) && isupper(c))
1094c2aa98e2SPeter Wemm 			c = tolower(c);
1095c2aa98e2SPeter Wemm 		hfunc = ((hfunc << 1) ^ c) % 2003;
1096c2aa98e2SPeter Wemm 	}
1097c2aa98e2SPeter Wemm 
1098c2aa98e2SPeter Wemm 	hfunc &= 0xff;
1099c2aa98e2SPeter Wemm 	hfunc++;
1100c2aa98e2SPeter Wemm 
1101c2aa98e2SPeter Wemm 	if (tTd(17, 9))
110240266059SGregory Neil Shapiro 		sm_dprintf(" = %d\n", hfunc);
1103c2aa98e2SPeter Wemm 	return hfunc;
1104c2aa98e2SPeter Wemm }
110540266059SGregory Neil Shapiro /*
1106c2aa98e2SPeter Wemm **  BESTMX -- find the best MX for a name
1107c2aa98e2SPeter Wemm **
1108c2aa98e2SPeter Wemm **	This is really a hack, but I don't see any obvious way
1109c2aa98e2SPeter Wemm **	to generalize it at the moment.
1110c2aa98e2SPeter Wemm */
1111c2aa98e2SPeter Wemm 
1112c2aa98e2SPeter Wemm /* ARGSUSED3 */
1113c2aa98e2SPeter Wemm char *
1114c2aa98e2SPeter Wemm bestmx_map_lookup(map, name, av, statp)
1115c2aa98e2SPeter Wemm 	MAP *map;
1116c2aa98e2SPeter Wemm 	char *name;
1117c2aa98e2SPeter Wemm 	char **av;
1118c2aa98e2SPeter Wemm 	int *statp;
1119c2aa98e2SPeter Wemm {
1120c2aa98e2SPeter Wemm 	int nmx;
1121c2aa98e2SPeter Wemm 	int saveopts = _res.options;
112240266059SGregory Neil Shapiro 	int i;
112340266059SGregory Neil Shapiro 	ssize_t len = 0;
112440266059SGregory Neil Shapiro 	char *result;
1125c2aa98e2SPeter Wemm 	char *mxhosts[MAXMXHOSTS + 1];
112640266059SGregory Neil Shapiro # if _FFR_BESTMX_BETTER_TRUNCATION
112740266059SGregory Neil Shapiro 	char *buf;
1128*5b0945b5SGregory Neil Shapiro # else
112940266059SGregory Neil Shapiro 	char *p;
1130065a643dSPeter Wemm 	char buf[PSBUFSIZE / 2];
1131*5b0945b5SGregory Neil Shapiro # endif
1132c2aa98e2SPeter Wemm 
1133c2aa98e2SPeter Wemm 	_res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
1134*5b0945b5SGregory Neil Shapiro 	nmx = getmxrr(name, mxhosts, NULL, 0, statp, NULL, -1);
1135c2aa98e2SPeter Wemm 	_res.options = saveopts;
1136c2aa98e2SPeter Wemm 	if (nmx <= 0)
1137c2aa98e2SPeter Wemm 		return NULL;
1138c2aa98e2SPeter Wemm 	if (bitset(MF_MATCHONLY, map->map_mflags))
1139c2aa98e2SPeter Wemm 		return map_rewrite(map, name, strlen(name), NULL);
1140c2aa98e2SPeter Wemm 	if ((map->map_coldelim == '\0') || (nmx == 1))
1141c2aa98e2SPeter Wemm 		return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
1142c2aa98e2SPeter Wemm 
1143c2aa98e2SPeter Wemm 	/*
1144c2aa98e2SPeter Wemm 	**  We were given a -z flag (return all MXs) and there are multiple
1145c2aa98e2SPeter Wemm 	**  ones.  We need to build them all into a list.
1146c2aa98e2SPeter Wemm 	*/
114740266059SGregory Neil Shapiro 
114840266059SGregory Neil Shapiro # if _FFR_BESTMX_BETTER_TRUNCATION
114940266059SGregory Neil Shapiro 	for (i = 0; i < nmx; i++)
115040266059SGregory Neil Shapiro 	{
115140266059SGregory Neil Shapiro 		if (strchr(mxhosts[i], map->map_coldelim) != NULL)
115240266059SGregory Neil Shapiro 		{
115340266059SGregory Neil Shapiro 			syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
115440266059SGregory Neil Shapiro 			       mxhosts[i], map->map_coldelim);
115540266059SGregory Neil Shapiro 			return NULL;
115640266059SGregory Neil Shapiro 		}
115740266059SGregory Neil Shapiro 		len += strlen(mxhosts[i]) + 1;
115840266059SGregory Neil Shapiro 		if (len < 0)
115940266059SGregory Neil Shapiro 		{
116040266059SGregory Neil Shapiro 			len -= strlen(mxhosts[i]) + 1;
116140266059SGregory Neil Shapiro 			break;
116240266059SGregory Neil Shapiro 		}
116340266059SGregory Neil Shapiro 	}
116440266059SGregory Neil Shapiro 	buf = (char *) sm_malloc(len);
116540266059SGregory Neil Shapiro 	if (buf == NULL)
116640266059SGregory Neil Shapiro 	{
116740266059SGregory Neil Shapiro 		*statp = EX_UNAVAILABLE;
116840266059SGregory Neil Shapiro 		return NULL;
116940266059SGregory Neil Shapiro 	}
117040266059SGregory Neil Shapiro 	*buf = '\0';
117140266059SGregory Neil Shapiro 	for (i = 0; i < nmx; i++)
117240266059SGregory Neil Shapiro 	{
117340266059SGregory Neil Shapiro 		int end;
117440266059SGregory Neil Shapiro 
117540266059SGregory Neil Shapiro 		end = sm_strlcat(buf, mxhosts[i], len);
117640266059SGregory Neil Shapiro 		if (i != nmx && end + 1 < len)
117740266059SGregory Neil Shapiro 		{
117840266059SGregory Neil Shapiro 			buf[end] = map->map_coldelim;
117940266059SGregory Neil Shapiro 			buf[end + 1] = '\0';
118040266059SGregory Neil Shapiro 		}
118140266059SGregory Neil Shapiro 	}
118240266059SGregory Neil Shapiro 
118340266059SGregory Neil Shapiro 	/* Cleanly truncate for rulesets */
118440266059SGregory Neil Shapiro 	truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim);
118540266059SGregory Neil Shapiro # else /* _FFR_BESTMX_BETTER_TRUNCATION */
1186c2aa98e2SPeter Wemm 	p = buf;
1187c2aa98e2SPeter Wemm 	for (i = 0; i < nmx; i++)
1188c2aa98e2SPeter Wemm 	{
118940266059SGregory Neil Shapiro 		size_t slen;
1190c2aa98e2SPeter Wemm 
1191c2aa98e2SPeter Wemm 		if (strchr(mxhosts[i], map->map_coldelim) != NULL)
1192c2aa98e2SPeter Wemm 		{
1193c2aa98e2SPeter Wemm 			syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
1194c2aa98e2SPeter Wemm 			       mxhosts[i], map->map_coldelim);
1195c2aa98e2SPeter Wemm 			return NULL;
1196c2aa98e2SPeter Wemm 		}
1197c2aa98e2SPeter Wemm 		slen = strlen(mxhosts[i]);
1198d0cef73dSGregory Neil Shapiro 		if (len + slen + 2 > sizeof(buf))
1199c2aa98e2SPeter Wemm 			break;
1200c2aa98e2SPeter Wemm 		if (i > 0)
1201c2aa98e2SPeter Wemm 		{
1202c2aa98e2SPeter Wemm 			*p++ = map->map_coldelim;
1203c2aa98e2SPeter Wemm 			len++;
1204c2aa98e2SPeter Wemm 		}
1205d0cef73dSGregory Neil Shapiro 		(void) sm_strlcpy(p, mxhosts[i], sizeof(buf) - len);
1206c2aa98e2SPeter Wemm 		p += slen;
1207c2aa98e2SPeter Wemm 		len += slen;
1208c2aa98e2SPeter Wemm 	}
120940266059SGregory Neil Shapiro # endif /* _FFR_BESTMX_BETTER_TRUNCATION */
121040266059SGregory Neil Shapiro 
121140266059SGregory Neil Shapiro 	result = map_rewrite(map, buf, len, av);
121240266059SGregory Neil Shapiro # if _FFR_BESTMX_BETTER_TRUNCATION
121340266059SGregory Neil Shapiro 	sm_free(buf);
1214*5b0945b5SGregory Neil Shapiro # endif
121540266059SGregory Neil Shapiro 	return result;
1216c2aa98e2SPeter Wemm }
121740266059SGregory Neil Shapiro /*
1218c2aa98e2SPeter Wemm **  DNS_GETCANONNAME -- get the canonical name for named host using DNS
1219c2aa98e2SPeter Wemm **
1220c2aa98e2SPeter Wemm **	This algorithm tries to be smart about wildcard MX records.
1221c2aa98e2SPeter Wemm **	This is hard to do because DNS doesn't tell is if we matched
1222c2aa98e2SPeter Wemm **	against a wildcard or a specific MX.
1223c2aa98e2SPeter Wemm **
1224c2aa98e2SPeter Wemm **	We always prefer A & CNAME records, since these are presumed
1225c2aa98e2SPeter Wemm **	to be specific.
1226c2aa98e2SPeter Wemm **
1227c2aa98e2SPeter Wemm **	If we match an MX in one pass and lose it in the next, we use
1228c2aa98e2SPeter Wemm **	the old one.  For example, consider an MX matching *.FOO.BAR.COM.
1229c2aa98e2SPeter Wemm **	A hostname bletch.foo.bar.com will match against this MX, but
1230c2aa98e2SPeter Wemm **	will stop matching when we try bletch.bar.com -- so we know
1231c2aa98e2SPeter Wemm **	that bletch.foo.bar.com must have been right.  This fails if
1232c2aa98e2SPeter Wemm **	there was also an MX record matching *.BAR.COM, but there are
1233c2aa98e2SPeter Wemm **	some things that just can't be fixed.
1234c2aa98e2SPeter Wemm **
1235c2aa98e2SPeter Wemm **	Parameters:
1236c2aa98e2SPeter Wemm **		host -- a buffer containing the name of the host.
1237c2aa98e2SPeter Wemm **			This is a value-result parameter.
1238c2aa98e2SPeter Wemm **		hbsize -- the size of the host buffer.
1239c2aa98e2SPeter Wemm **		trymx -- if set, try MX records as well as A and CNAME.
1240c2aa98e2SPeter Wemm **		statp -- pointer to place to store status.
124140266059SGregory Neil Shapiro **		pttl -- pointer to return TTL (can be NULL).
1242c2aa98e2SPeter Wemm **
1243c2aa98e2SPeter Wemm **	Returns:
1244*5b0945b5SGregory Neil Shapiro **		>0 -- if the host was found.
1245*5b0945b5SGregory Neil Shapiro **		0 -- otherwise.
1246c2aa98e2SPeter Wemm */
1247c2aa98e2SPeter Wemm 
1248*5b0945b5SGregory Neil Shapiro int
124940266059SGregory Neil Shapiro dns_getcanonname(host, hbsize, trymx, statp, pttl)
1250c2aa98e2SPeter Wemm 	char *host;
1251c2aa98e2SPeter Wemm 	int hbsize;
1252c2aa98e2SPeter Wemm 	bool trymx;
1253c2aa98e2SPeter Wemm 	int *statp;
125440266059SGregory Neil Shapiro 	int *pttl;
1255c2aa98e2SPeter Wemm {
125640266059SGregory Neil Shapiro 	register unsigned char *eom, *ap;
1257c2aa98e2SPeter Wemm 	register char *cp;
1258c2aa98e2SPeter Wemm 	register int n;
1259c2aa98e2SPeter Wemm 	HEADER *hp;
1260c2aa98e2SPeter Wemm 	querybuf answer;
1261*5b0945b5SGregory Neil Shapiro 	int ancount, qdcount, ret, type, qtype, initial, loopcnt, ttl, sli;
1262c2aa98e2SPeter Wemm 	char **domain;
1263*5b0945b5SGregory Neil Shapiro 	char *dp;
1264c2aa98e2SPeter Wemm 	char *mxmatch;
1265*5b0945b5SGregory Neil Shapiro 	bool amatch, gotmx, ad;
126640266059SGregory Neil Shapiro 	char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)];
1267*5b0945b5SGregory Neil Shapiro # if DNSSEC_TEST
1268*5b0945b5SGregory Neil Shapiro #  define ADDSL	1 /* NameSearchList may add another entry to searchlist! */
1269*5b0945b5SGregory Neil Shapiro # else
1270*5b0945b5SGregory Neil Shapiro #  define ADDSL	0
1271*5b0945b5SGregory Neil Shapiro # endif
1272*5b0945b5SGregory Neil Shapiro 	char *searchlist[MAXDNSRCH + 2 + ADDSL];
1273*5b0945b5SGregory Neil Shapiro # define SLSIZE SM_ARRAY_SIZE(searchlist)
1274*5b0945b5SGregory Neil Shapiro 	int (*resqdomain) __P((const char *, const char *, int, int, unsigned char *, int));
1275*5b0945b5SGregory Neil Shapiro # if DANE
1276*5b0945b5SGregory Neil Shapiro 	unsigned long old_options = 0;
1277*5b0945b5SGregory Neil Shapiro # endif
1278c2aa98e2SPeter Wemm 
1279*5b0945b5SGregory Neil Shapiro 	ttl = 0;
1280*5b0945b5SGregory Neil Shapiro 	gotmx = false;
1281*5b0945b5SGregory Neil Shapiro 	ad = true;
1282c2aa98e2SPeter Wemm 	if (tTd(8, 2))
128340266059SGregory Neil Shapiro 		sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
1284c2aa98e2SPeter Wemm 
1285c2aa98e2SPeter Wemm 	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
1286c2aa98e2SPeter Wemm 	{
1287c2aa98e2SPeter Wemm 		*statp = EX_UNAVAILABLE;
1288*5b0945b5SGregory Neil Shapiro 		return HOST_NOTFOUND;
1289c2aa98e2SPeter Wemm 	}
1290c2aa98e2SPeter Wemm 
1291*5b0945b5SGregory Neil Shapiro # if DANE
1292*5b0945b5SGregory Neil Shapiro 	old_options = _res.options;
1293*5b0945b5SGregory Neil Shapiro 	if (DANE_SECURE == Dane)
1294*5b0945b5SGregory Neil Shapiro 		_res.options |= SM_RES_DNSSEC;
1295*5b0945b5SGregory Neil Shapiro # endif
1296*5b0945b5SGregory Neil Shapiro 
1297193538b7SGregory Neil Shapiro 	*statp = EX_OK;
1298*5b0945b5SGregory Neil Shapiro 	resqdomain = res_querydomain;
1299*5b0945b5SGregory Neil Shapiro # if DNSSEC_TEST
1300*5b0945b5SGregory Neil Shapiro 	if (tTd(8, 110))
1301*5b0945b5SGregory Neil Shapiro 		resqdomain = tstdns_querydomain;
1302*5b0945b5SGregory Neil Shapiro # endif
1303193538b7SGregory Neil Shapiro 
1304c2aa98e2SPeter Wemm 	/*
1305c2aa98e2SPeter Wemm 	**  Initialize domain search list.  If there is at least one
1306c2aa98e2SPeter Wemm 	**  dot in the name, search the unmodified name first so we
1307c2aa98e2SPeter Wemm 	**  find "vse.CS" in Czechoslovakia instead of in the local
130806f25ae9SGregory Neil Shapiro 	**  domain (e.g., vse.CS.Berkeley.EDU).  Note that there is no
130906f25ae9SGregory Neil Shapiro 	**  longer a country named Czechoslovakia but this type of problem
131006f25ae9SGregory Neil Shapiro 	**  is still present.
1311c2aa98e2SPeter Wemm 	**
1312c2aa98e2SPeter Wemm 	**  Older versions of the resolver could create this
1313c2aa98e2SPeter Wemm 	**  list by tearing apart the host name.
1314c2aa98e2SPeter Wemm 	*/
1315c2aa98e2SPeter Wemm 
1316c2aa98e2SPeter Wemm 	loopcnt = 0;
1317c2aa98e2SPeter Wemm cnameloop:
1318c2aa98e2SPeter Wemm 	/* Check for dots in the name */
1319c2aa98e2SPeter Wemm 	for (cp = host, n = 0; *cp != '\0'; cp++)
1320c2aa98e2SPeter Wemm 		if (*cp == '.')
1321c2aa98e2SPeter Wemm 			n++;
1322c2aa98e2SPeter Wemm 
1323c2aa98e2SPeter Wemm 	/*
1324c2aa98e2SPeter Wemm 	**  Build the search list.
1325c2aa98e2SPeter Wemm 	**	If there is at least one dot in name, start with a null
1326c2aa98e2SPeter Wemm 	**	domain to search the unmodified name first.
1327c2aa98e2SPeter Wemm 	**	If name does not end with a dot and search up local domain
1328c2aa98e2SPeter Wemm 	**	tree desired, append each local domain component to the
1329c2aa98e2SPeter Wemm 	**	search list; if name contains no dots and default domain
1330c2aa98e2SPeter Wemm 	**	name is desired, append default domain name to search list;
1331c2aa98e2SPeter Wemm 	**	else if name ends in a dot, remove that dot.
1332c2aa98e2SPeter Wemm 	*/
1333c2aa98e2SPeter Wemm 
1334*5b0945b5SGregory Neil Shapiro 	sli = 0;
1335c2aa98e2SPeter Wemm 	if (n > 0)
1336*5b0945b5SGregory Neil Shapiro 		searchlist[sli++] = "";
1337*5b0945b5SGregory Neil Shapiro # if DNSSEC_TEST
1338*5b0945b5SGregory Neil Shapiro 	if (NameSearchList != NULL)
1339*5b0945b5SGregory Neil Shapiro 	{
1340*5b0945b5SGregory Neil Shapiro 		SM_ASSERT(sli < SLSIZE);
1341*5b0945b5SGregory Neil Shapiro 		searchlist[sli++] = NameSearchList;
1342*5b0945b5SGregory Neil Shapiro 	}
1343*5b0945b5SGregory Neil Shapiro # endif
1344c2aa98e2SPeter Wemm 	if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options))
1345c2aa98e2SPeter Wemm 	{
134606f25ae9SGregory Neil Shapiro 		/* make sure there are less than MAXDNSRCH domains */
134706f25ae9SGregory Neil Shapiro 		for (domain = RES_DNSRCH_VARIABLE, ret = 0;
1348*5b0945b5SGregory Neil Shapiro 		     *domain != NULL && ret < MAXDNSRCH && sli < SLSIZE;
134906f25ae9SGregory Neil Shapiro 		     ret++)
1350*5b0945b5SGregory Neil Shapiro 			searchlist[sli++] = *domain++;
1351c2aa98e2SPeter Wemm 	}
1352c2aa98e2SPeter Wemm 	else if (n == 0 && bitset(RES_DEFNAMES, _res.options))
1353c2aa98e2SPeter Wemm 	{
1354*5b0945b5SGregory Neil Shapiro 		SM_ASSERT(sli < SLSIZE);
1355*5b0945b5SGregory Neil Shapiro 		searchlist[sli++] = _res.defdname;
1356c2aa98e2SPeter Wemm 	}
1357c2aa98e2SPeter Wemm 	else if (*cp == '.')
1358c2aa98e2SPeter Wemm 	{
1359c2aa98e2SPeter Wemm 		*cp = '\0';
1360c2aa98e2SPeter Wemm 	}
1361*5b0945b5SGregory Neil Shapiro 	SM_ASSERT(sli < SLSIZE);
1362*5b0945b5SGregory Neil Shapiro 	searchlist[sli] = NULL;
1363c2aa98e2SPeter Wemm 
1364c2aa98e2SPeter Wemm 	/*
1365c2aa98e2SPeter Wemm 	**  Now loop through the search list, appending each domain in turn
1366c2aa98e2SPeter Wemm 	**  name and searching for a match.
1367c2aa98e2SPeter Wemm 	*/
1368c2aa98e2SPeter Wemm 
1369c2aa98e2SPeter Wemm 	mxmatch = NULL;
1370a7ec597cSGregory Neil Shapiro 	initial = T_A;
1371a7ec597cSGregory Neil Shapiro # if NETINET6
1372a7ec597cSGregory Neil Shapiro 	if (InetMode == AF_INET6)
1373a7ec597cSGregory Neil Shapiro 		initial = T_AAAA;
1374*5b0945b5SGregory Neil Shapiro # endif
1375a7ec597cSGregory Neil Shapiro 	qtype = initial;
1376c2aa98e2SPeter Wemm 
1377*5b0945b5SGregory Neil Shapiro 	for (sli = 0; sli < SLSIZE; )
1378c2aa98e2SPeter Wemm 	{
1379*5b0945b5SGregory Neil Shapiro 		dp = searchlist[sli];
1380*5b0945b5SGregory Neil Shapiro 		if (NULL == dp)
1381*5b0945b5SGregory Neil Shapiro 			break;
1382a7ec597cSGregory Neil Shapiro 		if (qtype == initial)
138340266059SGregory Neil Shapiro 			gotmx = false;
1384c2aa98e2SPeter Wemm 		if (tTd(8, 5))
138540266059SGregory Neil Shapiro 			sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n",
1386*5b0945b5SGregory Neil Shapiro 				host, dp,
138706f25ae9SGregory Neil Shapiro # if NETINET6
138806f25ae9SGregory Neil Shapiro 				qtype == T_AAAA ? "AAAA" :
1389*5b0945b5SGregory Neil Shapiro # endif
139006f25ae9SGregory Neil Shapiro 				qtype == T_A ? "A" :
139106f25ae9SGregory Neil Shapiro 				qtype == T_MX ? "MX" :
139206f25ae9SGregory Neil Shapiro 				"???");
1393193538b7SGregory Neil Shapiro 		errno = 0;
1394*5b0945b5SGregory Neil Shapiro 		hp = (HEADER *) &answer;
1395*5b0945b5SGregory Neil Shapiro 		ret = (*resqdomain)(host, dp, C_IN, qtype,
1396c2aa98e2SPeter Wemm 				      answer.qb2, sizeof(answer.qb2));
1397c2aa98e2SPeter Wemm 		if (ret <= 0)
1398c2aa98e2SPeter Wemm 		{
139940266059SGregory Neil Shapiro 			int save_errno = errno;
1400c2aa98e2SPeter Wemm 
140140266059SGregory Neil Shapiro 			if (tTd(8, 7))
140240266059SGregory Neil Shapiro 				sm_dprintf("\tNO: errno=%d, h_errno=%d\n",
140340266059SGregory Neil Shapiro 					   save_errno, h_errno);
140440266059SGregory Neil Shapiro 
140540266059SGregory Neil Shapiro 			if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN)
1406c2aa98e2SPeter Wemm 			{
1407193538b7SGregory Neil Shapiro 				/*
140840266059SGregory Neil Shapiro 				**  the name server seems to be down or broken.
1409193538b7SGregory Neil Shapiro 				*/
1410193538b7SGregory Neil Shapiro 
1411602a2b1bSGregory Neil Shapiro 				SM_SET_H_ERRNO(TRY_AGAIN);
1412*5b0945b5SGregory Neil Shapiro 				if (*dp == '\0')
1413605302a5SGregory Neil Shapiro 				{
1414605302a5SGregory Neil Shapiro 					if (*statp == EX_OK)
1415605302a5SGregory Neil Shapiro 						*statp = EX_TEMPFAIL;
1416605302a5SGregory Neil Shapiro 					goto nexttype;
1417605302a5SGregory Neil Shapiro 				}
1418c2aa98e2SPeter Wemm 				*statp = EX_TEMPFAIL;
141906f25ae9SGregory Neil Shapiro 
1420602a2b1bSGregory Neil Shapiro 				if (WorkAroundBrokenAAAA)
1421602a2b1bSGregory Neil Shapiro 				{
1422193538b7SGregory Neil Shapiro 					/*
1423193538b7SGregory Neil Shapiro 					**  Only return if not TRY_AGAIN as an
1424193538b7SGregory Neil Shapiro 					**  attempt with a different qtype may
1425193538b7SGregory Neil Shapiro 					**  succeed (res_querydomain() calls
1426193538b7SGregory Neil Shapiro 					**  res_query() calls res_send() which
1427193538b7SGregory Neil Shapiro 					**  sets errno to ETIMEDOUT if the
1428193538b7SGregory Neil Shapiro 					**  nameservers could be contacted but
1429193538b7SGregory Neil Shapiro 					**  didn't give an answer).
1430193538b7SGregory Neil Shapiro 					*/
1431193538b7SGregory Neil Shapiro 
143240266059SGregory Neil Shapiro 					if (save_errno != ETIMEDOUT)
1433*5b0945b5SGregory Neil Shapiro 						goto error;
1434602a2b1bSGregory Neil Shapiro 				}
143540266059SGregory Neil Shapiro 				else
1436*5b0945b5SGregory Neil Shapiro 					goto error;
1437c2aa98e2SPeter Wemm 			}
1438c2aa98e2SPeter Wemm 
1439605302a5SGregory Neil Shapiro nexttype:
1440c2aa98e2SPeter Wemm 			if (h_errno != HOST_NOT_FOUND)
1441c2aa98e2SPeter Wemm 			{
1442c2aa98e2SPeter Wemm 				/* might have another type of interest */
144306f25ae9SGregory Neil Shapiro # if NETINET6
144440266059SGregory Neil Shapiro 				if (qtype == T_AAAA)
144506f25ae9SGregory Neil Shapiro 				{
1446c2aa98e2SPeter Wemm 					qtype = T_A;
1447c2aa98e2SPeter Wemm 					continue;
1448c2aa98e2SPeter Wemm 				}
144940266059SGregory Neil Shapiro 				else
145006f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
145140266059SGregory Neil Shapiro 				if (qtype == T_A && !gotmx &&
1452*5b0945b5SGregory Neil Shapiro 				    (trymx || *dp == '\0'))
1453c2aa98e2SPeter Wemm 				{
1454c2aa98e2SPeter Wemm 					qtype = T_MX;
1455c2aa98e2SPeter Wemm 					continue;
1456c2aa98e2SPeter Wemm 				}
1457c2aa98e2SPeter Wemm 			}
1458c2aa98e2SPeter Wemm 
1459c2aa98e2SPeter Wemm 			/* definite no -- try the next domain */
1460*5b0945b5SGregory Neil Shapiro 			sli++;
1461a7ec597cSGregory Neil Shapiro 			qtype = initial;
1462c2aa98e2SPeter Wemm 			continue;
1463c2aa98e2SPeter Wemm 		}
1464c2aa98e2SPeter Wemm 		else if (tTd(8, 7))
146540266059SGregory Neil Shapiro 			sm_dprintf("\tYES\n");
1466c2aa98e2SPeter Wemm 
1467c2aa98e2SPeter Wemm 		/* avoid problems after truncation in tcp packets */
1468c2aa98e2SPeter Wemm 		if (ret > sizeof(answer))
1469c2aa98e2SPeter Wemm 			ret = sizeof(answer);
1470af9557fdSGregory Neil Shapiro 		SM_ASSERT(ret >= 0);
1471c2aa98e2SPeter Wemm 
1472c2aa98e2SPeter Wemm 		/*
1473c2aa98e2SPeter Wemm 		**  Appear to have a match.  Confirm it by searching for A or
1474c2aa98e2SPeter Wemm 		**  CNAME records.  If we don't have a local domain
1475c2aa98e2SPeter Wemm 		**  wild card MX record, we will accept MX as well.
1476c2aa98e2SPeter Wemm 		*/
1477c2aa98e2SPeter Wemm 
147840266059SGregory Neil Shapiro 		ap = (unsigned char *) &answer + HFIXEDSZ;
147940266059SGregory Neil Shapiro 		eom = (unsigned char *) &answer + ret;
1480c2aa98e2SPeter Wemm 
1481*5b0945b5SGregory Neil Shapiro 		if (0 == hp->ad)
1482*5b0945b5SGregory Neil Shapiro 			ad = false;
1483*5b0945b5SGregory Neil Shapiro 
1484c2aa98e2SPeter Wemm 		/* skip question part of response -- we know what we asked */
148540266059SGregory Neil Shapiro 		for (qdcount = ntohs((unsigned short) hp->qdcount);
148606f25ae9SGregory Neil Shapiro 		     qdcount--;
148706f25ae9SGregory Neil Shapiro 		     ap += ret + QFIXEDSZ)
1488c2aa98e2SPeter Wemm 		{
1489c2aa98e2SPeter Wemm 			if ((ret = dn_skipname(ap, eom)) < 0)
1490c2aa98e2SPeter Wemm 			{
1491c2aa98e2SPeter Wemm 				if (tTd(8, 20))
149240266059SGregory Neil Shapiro 					sm_dprintf("qdcount failure (%d)\n",
149340266059SGregory Neil Shapiro 						ntohs((unsigned short) hp->qdcount));
1494c2aa98e2SPeter Wemm 				*statp = EX_SOFTWARE;
1495*5b0945b5SGregory Neil Shapiro 				goto error;
1496c2aa98e2SPeter Wemm 			}
1497c2aa98e2SPeter Wemm 		}
1498c2aa98e2SPeter Wemm 
149940266059SGregory Neil Shapiro 		amatch = false;
150040266059SGregory Neil Shapiro 		for (ancount = ntohs((unsigned short) hp->ancount);
150106f25ae9SGregory Neil Shapiro 		     --ancount >= 0 && ap < eom;
1502c2aa98e2SPeter Wemm 		     ap += n)
1503c2aa98e2SPeter Wemm 		{
150440266059SGregory Neil Shapiro 			n = dn_expand((unsigned char *) &answer, eom, ap,
1505d0cef73dSGregory Neil Shapiro 				      (RES_UNC_T) nbuf, sizeof(nbuf));
1506c2aa98e2SPeter Wemm 			if (n < 0)
1507c2aa98e2SPeter Wemm 				break;
1508c2aa98e2SPeter Wemm 			ap += n;
1509c2aa98e2SPeter Wemm 			GETSHORT(type, ap);
151040266059SGregory Neil Shapiro 			ap += INT16SZ;		/* skip over class */
151140266059SGregory Neil Shapiro 			GETLONG(ttl, ap);
151240266059SGregory Neil Shapiro 			GETSHORT(n, ap);	/* rdlength */
1513c2aa98e2SPeter Wemm 			switch (type)
1514c2aa98e2SPeter Wemm 			{
1515c2aa98e2SPeter Wemm 			  case T_MX:
151640266059SGregory Neil Shapiro 				gotmx = true;
1517*5b0945b5SGregory Neil Shapiro 				if (*dp != '\0' && HasWildcardMX)
1518c2aa98e2SPeter Wemm 				{
1519c2aa98e2SPeter Wemm 					/*
1520c2aa98e2SPeter Wemm 					**  If we are using MX matches and have
1521c2aa98e2SPeter Wemm 					**  not yet gotten one, save this one
1522c2aa98e2SPeter Wemm 					**  but keep searching for an A or
1523c2aa98e2SPeter Wemm 					**  CNAME match.
1524c2aa98e2SPeter Wemm 					*/
1525c2aa98e2SPeter Wemm 
1526c2aa98e2SPeter Wemm 					if (trymx && mxmatch == NULL)
1527*5b0945b5SGregory Neil Shapiro 						mxmatch = dp;
1528c2aa98e2SPeter Wemm 					continue;
1529c2aa98e2SPeter Wemm 				}
1530c2aa98e2SPeter Wemm 
1531c2aa98e2SPeter Wemm 				/*
1532c2aa98e2SPeter Wemm 				**  If we did not append a domain name, this
1533c2aa98e2SPeter Wemm 				**  must have been a canonical name to start
1534c2aa98e2SPeter Wemm 				**  with.  Even if we did append a domain name,
1535c2aa98e2SPeter Wemm 				**  in the absence of a wildcard MX this must
1536c2aa98e2SPeter Wemm 				**  still be a real MX match.
1537c2aa98e2SPeter Wemm 				**  Such MX matches are as good as an A match,
1538c2aa98e2SPeter Wemm 				**  fall through.
1539c2aa98e2SPeter Wemm 				*/
154006f25ae9SGregory Neil Shapiro 				/* FALLTHROUGH */
154106f25ae9SGregory Neil Shapiro 
154206f25ae9SGregory Neil Shapiro # if NETINET6
154306f25ae9SGregory Neil Shapiro 			  case T_AAAA:
1544*5b0945b5SGregory Neil Shapiro # endif
1545c2aa98e2SPeter Wemm 			  case T_A:
1546c2aa98e2SPeter Wemm 				/* Flag that a good match was found */
154740266059SGregory Neil Shapiro 				amatch = true;
1548c2aa98e2SPeter Wemm 
1549c2aa98e2SPeter Wemm 				/* continue in case a CNAME also exists */
1550c2aa98e2SPeter Wemm 				continue;
1551c2aa98e2SPeter Wemm 
1552c2aa98e2SPeter Wemm 			  case T_CNAME:
1553c2aa98e2SPeter Wemm 				if (DontExpandCnames)
1554c2aa98e2SPeter Wemm 				{
1555c2aa98e2SPeter Wemm 					/* got CNAME -- guaranteed canonical */
155640266059SGregory Neil Shapiro 					amatch = true;
1557c2aa98e2SPeter Wemm 					break;
1558c2aa98e2SPeter Wemm 				}
1559c2aa98e2SPeter Wemm 
1560c2aa98e2SPeter Wemm 				if (loopcnt++ > MAXCNAMEDEPTH)
1561c2aa98e2SPeter Wemm 				{
1562c2aa98e2SPeter Wemm 					/*XXX should notify postmaster XXX*/
1563c2aa98e2SPeter Wemm 					message("DNS failure: CNAME loop for %s",
1564c2aa98e2SPeter Wemm 						host);
1565c2aa98e2SPeter Wemm 					if (CurEnv->e_message == NULL)
1566c2aa98e2SPeter Wemm 					{
1567c2aa98e2SPeter Wemm 						char ebuf[MAXLINE];
1568c2aa98e2SPeter Wemm 
156940266059SGregory Neil Shapiro 						(void) sm_snprintf(ebuf,
1570d0cef73dSGregory Neil Shapiro 							sizeof(ebuf),
1571c2aa98e2SPeter Wemm 							"Deferred: DNS failure: CNAME loop for %.100s",
1572c2aa98e2SPeter Wemm 							host);
157340266059SGregory Neil Shapiro 						CurEnv->e_message =
157440266059SGregory Neil Shapiro 						    sm_rpool_strdup_x(
157540266059SGregory Neil Shapiro 							CurEnv->e_rpool, ebuf);
1576c2aa98e2SPeter Wemm 					}
1577602a2b1bSGregory Neil Shapiro 					SM_SET_H_ERRNO(NO_RECOVERY);
1578c2aa98e2SPeter Wemm 					*statp = EX_CONFIG;
1579*5b0945b5SGregory Neil Shapiro 					goto error;
1580c2aa98e2SPeter Wemm 				}
1581c2aa98e2SPeter Wemm 
1582c2aa98e2SPeter Wemm 				/* value points at name */
158340266059SGregory Neil Shapiro 				if ((ret = dn_expand((unsigned char *)&answer,
158440266059SGregory Neil Shapiro 						     eom, ap, (RES_UNC_T) nbuf,
158540266059SGregory Neil Shapiro 						     sizeof(nbuf))) < 0)
1586c2aa98e2SPeter Wemm 					break;
158740266059SGregory Neil Shapiro 				(void) sm_strlcpy(host, nbuf, hbsize);
1588c2aa98e2SPeter Wemm 
1589c2aa98e2SPeter Wemm 				/*
1590c2aa98e2SPeter Wemm 				**  RFC 1034 section 3.6 specifies that CNAME
1591c2aa98e2SPeter Wemm 				**  should point at the canonical name -- but
1592c2aa98e2SPeter Wemm 				**  urges software to try again anyway.
1593c2aa98e2SPeter Wemm 				*/
1594c2aa98e2SPeter Wemm 
1595c2aa98e2SPeter Wemm 				goto cnameloop;
1596c2aa98e2SPeter Wemm 
1597c2aa98e2SPeter Wemm 			  default:
1598c2aa98e2SPeter Wemm 				/* not a record of interest */
1599c2aa98e2SPeter Wemm 				continue;
1600c2aa98e2SPeter Wemm 			}
1601c2aa98e2SPeter Wemm 		}
1602c2aa98e2SPeter Wemm 
1603c2aa98e2SPeter Wemm 		if (amatch)
1604c2aa98e2SPeter Wemm 		{
1605c2aa98e2SPeter Wemm 			/*
1606c2aa98e2SPeter Wemm 			**  Got a good match -- either an A, CNAME, or an
1607c2aa98e2SPeter Wemm 			**  exact MX record.  Save it and get out of here.
1608c2aa98e2SPeter Wemm 			*/
1609c2aa98e2SPeter Wemm 
1610*5b0945b5SGregory Neil Shapiro 			mxmatch = dp;
1611c2aa98e2SPeter Wemm 			break;
1612c2aa98e2SPeter Wemm 		}
1613c2aa98e2SPeter Wemm 
1614c2aa98e2SPeter Wemm 		/*
1615c2aa98e2SPeter Wemm 		**  Nothing definitive yet.
1616c2aa98e2SPeter Wemm 		**	If this was a T_A query and we haven't yet found a MX
1617c2aa98e2SPeter Wemm 		**		match, try T_MX if allowed to do so.
1618c2aa98e2SPeter Wemm 		**	Otherwise, try the next domain.
1619c2aa98e2SPeter Wemm 		*/
1620c2aa98e2SPeter Wemm 
162106f25ae9SGregory Neil Shapiro # if NETINET6
162240266059SGregory Neil Shapiro 		if (qtype == T_AAAA)
1623c2aa98e2SPeter Wemm 			qtype = T_A;
162440266059SGregory Neil Shapiro 		else
1625*5b0945b5SGregory Neil Shapiro # endif
1626*5b0945b5SGregory Neil Shapiro 		if (qtype == T_A && !gotmx && (trymx || *dp == '\0'))
1627c2aa98e2SPeter Wemm 			qtype = T_MX;
1628c2aa98e2SPeter Wemm 		else
1629c2aa98e2SPeter Wemm 		{
1630a7ec597cSGregory Neil Shapiro 			qtype = initial;
1631*5b0945b5SGregory Neil Shapiro 			sli++;
1632c2aa98e2SPeter Wemm 		}
1633c2aa98e2SPeter Wemm 	}
1634c2aa98e2SPeter Wemm 
1635c2aa98e2SPeter Wemm 	/* if nothing was found, we are done */
1636c2aa98e2SPeter Wemm 	if (mxmatch == NULL)
1637c2aa98e2SPeter Wemm 	{
1638193538b7SGregory Neil Shapiro 		if (*statp == EX_OK)
1639c2aa98e2SPeter Wemm 			*statp = EX_NOHOST;
1640*5b0945b5SGregory Neil Shapiro 		goto error;
1641c2aa98e2SPeter Wemm 	}
1642c2aa98e2SPeter Wemm 
1643c2aa98e2SPeter Wemm 	/*
1644c2aa98e2SPeter Wemm 	**  Create canonical name and return.
1645c2aa98e2SPeter Wemm 	**  If saved domain name is null, name was already canonical.
1646c2aa98e2SPeter Wemm 	**  Otherwise append the saved domain name.
1647c2aa98e2SPeter Wemm 	*/
1648c2aa98e2SPeter Wemm 
1649d0cef73dSGregory Neil Shapiro 	(void) sm_snprintf(nbuf, sizeof(nbuf), "%.*s%s%.*s", MAXDNAME, host,
1650c2aa98e2SPeter Wemm 			   *mxmatch == '\0' ? "" : ".",
1651c2aa98e2SPeter Wemm 			   MAXDNAME, mxmatch);
165240266059SGregory Neil Shapiro 	(void) sm_strlcpy(host, nbuf, hbsize);
1653c2aa98e2SPeter Wemm 	if (tTd(8, 5))
165440266059SGregory Neil Shapiro 		sm_dprintf("dns_getcanonname: %s\n", host);
1655c2aa98e2SPeter Wemm 	*statp = EX_OK;
165640266059SGregory Neil Shapiro 
165740266059SGregory Neil Shapiro 	/* return only one TTL entry, that should be sufficient */
165840266059SGregory Neil Shapiro 	if (ttl > 0 && pttl != NULL)
165940266059SGregory Neil Shapiro 		*pttl = ttl;
1660*5b0945b5SGregory Neil Shapiro # if DANE
1661*5b0945b5SGregory Neil Shapiro 	_res.options = old_options;
1662*5b0945b5SGregory Neil Shapiro # endif
1663*5b0945b5SGregory Neil Shapiro 	return ad ? HOST_SECURE : HOST_OK;
1664*5b0945b5SGregory Neil Shapiro 
1665*5b0945b5SGregory Neil Shapiro   error:
1666*5b0945b5SGregory Neil Shapiro # if DANE
1667*5b0945b5SGregory Neil Shapiro 	_res.options = old_options;
1668*5b0945b5SGregory Neil Shapiro # endif
1669*5b0945b5SGregory Neil Shapiro 	return HOST_NOTFOUND;
1670c2aa98e2SPeter Wemm }
1671*5b0945b5SGregory Neil Shapiro 
1672c2aa98e2SPeter Wemm #endif /* NAMED_BIND */
1673