1/*
2 * Copyright (c) 2000-2004, 2010, 2015, 2020 Proofpoint, Inc. and its suppliers.
3 *	All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 *
9 */
10
11/*
12 * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H�gskolan
13 * (Royal Institute of Technology, Stockholm, Sweden).
14 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 * 1. Redistributions of source code must retain the above copyright
21 *    notice, this list of conditions and the following disclaimer.
22 *
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 *
27 * 3. Neither the name of the Institute nor the names of its contributors
28 *    may be used to endorse or promote products derived from this software
29 *    without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * SUCH DAMAGE.
42 */
43
44#include <sendmail.h>
45#if DNSMAP || DANE
46# if NAMED_BIND
47#  if NETINET
48#   include <netinet/in_systm.h>
49#   include <netinet/ip.h>
50#  endif
51#  define _DEFINE_SMR_GLOBALS 1
52#  include "sm_resolve.h"
53
54#include <arpa/inet.h>
55
56SM_RCSID("$Id: sm_resolve.c,v 8.40 2013-11-22 20:51:56 ca Exp $")
57
58static struct stot
59{
60	const char	*st_name;
61	int		st_type;
62} stot[] =
63{
64#  if NETINET
65	{	"A",		T_A		},
66#  endif
67#  if NETINET6
68	{	"AAAA",		T_AAAA		},
69#  endif
70	{	"NS",		T_NS		},
71	{	"CNAME",	T_CNAME		},
72	{	"PTR",		T_PTR		},
73	{	"MX",		T_MX		},
74	{	"TXT",		T_TXT		},
75	{	"AFSDB",	T_AFSDB		},
76	{	"SRV",		T_SRV		},
77#  ifdef T_DS
78	{	"DS",		T_DS		},
79#  endif
80	{	"RRSIG",	T_RRSIG		},
81#  ifdef T_NSEC
82	{	"NSEC",		T_NSEC		},
83#  endif
84#  ifdef T_DNSKEY
85	{	"DNSKEY",	T_DNSKEY	},
86#  endif
87	{	"TLSA",		T_TLSA		},
88	{	NULL,		0		}
89};
90
91static DNS_REPLY_T *parse_dns_reply __P((unsigned char *, int, unsigned int));
92#  if DNSSEC_TEST && defined(T_TLSA)
93static char *hex2bin __P((const char *, int));
94#  endif
95
96/*
97**  DNS_STRING_TO_TYPE -- convert resource record name into type
98**
99**	Parameters:
100**		name -- name of resource record type
101**
102**	Returns:
103**		type if succeeded.
104**		-1 otherwise.
105*/
106
107int
108dns_string_to_type(name)
109	const char *name;
110{
111	struct stot *p = stot;
112
113	for (p = stot; p->st_name != NULL; p++)
114		if (sm_strcasecmp(name, p->st_name) == 0)
115			return p->st_type;
116	return -1;
117}
118
119/*
120**  DNS_TYPE_TO_STRING -- convert resource record type into name
121**
122**	Parameters:
123**		type -- resource record type
124**
125**	Returns:
126**		name if succeeded.
127**		NULL otherwise.
128*/
129
130const char *
131dns_type_to_string(type)
132	int type;
133{
134	struct stot *p = stot;
135
136	for (p = stot; p->st_name != NULL; p++)
137		if (type == p->st_type)
138			return p->st_name;
139	return NULL;
140}
141
142/*
143**  DNS_FREE_DATA -- free all components of a DNS_REPLY_T
144**
145**	Parameters:
146**		dr -- pointer to DNS_REPLY_T
147**
148**	Returns:
149**		none.
150*/
151
152void
153dns_free_data(dr)
154	DNS_REPLY_T *dr;
155{
156	RESOURCE_RECORD_T *rr;
157
158	if (dr == NULL)
159		return;
160	if (dr->dns_r_q.dns_q_domain != NULL)
161		sm_free(dr->dns_r_q.dns_q_domain);
162	for (rr = dr->dns_r_head; rr != NULL; )
163	{
164		RESOURCE_RECORD_T *tmp = rr;
165
166		if (rr->rr_domain != NULL)
167			sm_free(rr->rr_domain);
168		if (rr->rr_u.rr_data != NULL)
169			sm_free(rr->rr_u.rr_data);
170		rr = rr->rr_next;
171		sm_free(tmp);
172	}
173	sm_free(dr);
174}
175
176/*
177**  BIN2HEX -- convert binary TLSA RR to hex string
178**
179**	Parameters:
180**		tlsa -- pointer to result (allocated here)
181**		p --  binary data (TLSA RR)
182**		size -- length of p
183**		min_size -- minimum expected size
184**
185**	Returns:
186**		>0: length of string (*tlsa)
187**		-1: error
188*/
189
190static int bin2hex __P((char **, unsigned char *, int, int));
191
192static int
193bin2hex(tlsa, p, size, min_size)
194	char **tlsa;
195	unsigned char *p;
196	int size;
197	int min_size;
198{
199	int i, pos, txtlen;
200
201	txtlen = size * 3;
202	if (txtlen <= size || size < min_size)
203	{
204		if (LogLevel > 5)
205			sm_syslog(LOG_WARNING, NOQID,
206				  "ERROR: bin2hex: size %d wrong", size);
207		return -1;
208	}
209	*tlsa = (char *) sm_malloc(txtlen);
210	if (*tlsa == NULL)
211	{
212		if (tTd(8, 17))
213			sm_dprintf("len=%d, rr_data=NULL\n", txtlen);
214		return -1;
215	}
216	snprintf(*tlsa, txtlen,
217		"%02X %02X %02X", p[0], p[1], p[2]);
218	pos = strlen(*tlsa);
219
220	/* why isn't there a print function like strlcat? */
221	for (i = 3; i < size && pos < txtlen; i++, pos += 3)
222		snprintf(*tlsa + pos, txtlen - pos, "%c%02X",
223			(i == 3) ? ' ' : ':', p[i]);
224
225	return i;
226}
227
228/*
229**  PARSE_DNS_REPLY -- parse DNS reply data.
230**
231**	Parameters:
232**		data -- pointer to dns data
233**		len -- len of data
234**		flags -- flags (RR_*)
235**
236**	Returns:
237**		pointer to DNS_REPLY_T if succeeded.
238**		NULL otherwise.
239**
240**	Note:
241**		use dns_free_data() to free() the result when no longer needed.
242*/
243
244static DNS_REPLY_T *
245parse_dns_reply(data, len, flags)
246	unsigned char *data;
247	int len;
248	unsigned int flags;
249{
250	unsigned char *p;
251	unsigned short ans_cnt, ui;
252	int status;
253	size_t l;
254	char host[MAXHOSTNAMELEN];
255	DNS_REPLY_T *dr;
256	RESOURCE_RECORD_T **rr;
257
258	if (tTd(8, 90))
259	{
260		FILE *fp;
261
262		fp = fopen("dns.buffer", "w");
263		if (fp != NULL)
264		{
265			fwrite(data, 1, len, fp);
266			fclose(fp);
267			fp = NULL;
268		}
269		else
270			sm_dprintf("parse_dns_reply: fp=%p, e=%d\n",
271				(void *)fp, errno);
272	}
273
274	dr = (DNS_REPLY_T *) sm_malloc(sizeof(*dr));
275	if (dr == NULL)
276		return NULL;
277	memset(dr, 0, sizeof(*dr));
278
279	p = data;
280
281	/* doesn't work on Crays? */
282	memcpy(&dr->dns_r_h, p, sizeof(dr->dns_r_h));
283	p += sizeof(dr->dns_r_h);
284	status = dn_expand(data, data + len, p, host, sizeof(host));
285	if (status < 0)
286		goto error;
287	dr->dns_r_q.dns_q_domain = sm_strdup(host);
288	if (dr->dns_r_q.dns_q_domain == NULL)
289		goto error;
290
291	ans_cnt = ntohs((unsigned short) dr->dns_r_h.ancount);
292	if (tTd(8, 17))
293		sm_dprintf("parse_dns_reply: ac=%d, ad=%d\n", ans_cnt,
294			dr->dns_r_h.ad);
295
296	p += status;
297	GETSHORT(dr->dns_r_q.dns_q_type, p);
298	GETSHORT(dr->dns_r_q.dns_q_class, p);
299	rr = &dr->dns_r_head;
300	ui = 0;
301	while (p < data + len && ui < ans_cnt)
302	{
303		int type, class, ttl, size, txtlen;
304
305		status = dn_expand(data, data + len, p, host, sizeof(host));
306		if (status < 0)
307			goto error;
308		++ui;
309		p += status;
310		GETSHORT(type, p);
311		GETSHORT(class, p);
312		GETLONG(ttl, p);
313		GETSHORT(size, p);
314		if (p + size > data + len)
315		{
316			/*
317			**  announced size of data exceeds length of
318			**  data paket: someone is cheating.
319			*/
320
321			if (LogLevel > 5)
322				sm_syslog(LOG_WARNING, NOQID,
323					  "ERROR: DNS RDLENGTH=%d > data len=%d",
324					  size, len - (int)(p - data));
325			goto error;
326		}
327		*rr = (RESOURCE_RECORD_T *) sm_malloc(sizeof(**rr));
328		if (*rr == NULL)
329			goto error;
330		memset(*rr, 0, sizeof(**rr));
331		(*rr)->rr_domain = sm_strdup(host);
332		if ((*rr)->rr_domain == NULL)
333			goto error;
334		(*rr)->rr_type = type;
335		(*rr)->rr_class = class;
336		(*rr)->rr_ttl = ttl;
337		(*rr)->rr_size = size;
338		switch (type)
339		{
340		  case T_NS:
341		  case T_CNAME:
342		  case T_PTR:
343			status = dn_expand(data, data + len, p, host,
344					   sizeof(host));
345			if (status < 0)
346				goto error;
347			if (tTd(8, 50))
348				sm_dprintf("parse_dns_reply: type=%s, host=%s\n",
349					dns_type_to_string(type), host);
350			(*rr)->rr_u.rr_txt = sm_strdup(host);
351			if ((*rr)->rr_u.rr_txt == NULL)
352				goto error;
353			break;
354
355		  case T_MX:
356		  case T_AFSDB:
357			status = dn_expand(data, data + len, p + 2, host,
358					   sizeof(host));
359			if (status < 0)
360				goto error;
361			l = strlen(host) + 1;
362			(*rr)->rr_u.rr_mx = (MX_RECORD_T *)
363				sm_malloc(sizeof(*((*rr)->rr_u.rr_mx)) + l);
364			if ((*rr)->rr_u.rr_mx == NULL)
365				goto error;
366			(*rr)->rr_u.rr_mx->mx_r_preference = (p[0] << 8) | p[1];
367			(void) sm_strlcpy((*rr)->rr_u.rr_mx->mx_r_domain,
368					  host, l);
369			if (tTd(8, 50))
370				sm_dprintf("mx=%s, pref=%d\n", host,
371					(*rr)->rr_u.rr_mx->mx_r_preference);
372			break;
373
374		  case T_SRV:
375			status = dn_expand(data, data + len, p + 6, host,
376					   sizeof(host));
377			if (status < 0)
378				goto error;
379			l = strlen(host) + 1;
380			(*rr)->rr_u.rr_srv = (SRV_RECORDT_T*)
381				sm_malloc(sizeof(*((*rr)->rr_u.rr_srv)) + l);
382			if ((*rr)->rr_u.rr_srv == NULL)
383				goto error;
384			(*rr)->rr_u.rr_srv->srv_r_priority = (p[0] << 8) | p[1];
385			(*rr)->rr_u.rr_srv->srv_r_weight = (p[2] << 8) | p[3];
386			(*rr)->rr_u.rr_srv->srv_r_port = (p[4] << 8) | p[5];
387			(void) sm_strlcpy((*rr)->rr_u.rr_srv->srv_r_target,
388					  host, l);
389			break;
390
391		  case T_TXT:
392
393			/*
394			**  The TXT record contains the length as
395			**  leading byte, hence the value is restricted
396			**  to 255, which is less than the maximum value
397			**  of RDLENGTH (size). Nevertheless, txtlen
398			**  must be less than size because the latter
399			**  specifies the length of the entire TXT
400			**  record.
401			*/
402
403			txtlen = *p;
404			if (txtlen >= size)
405			{
406				if (LogLevel > 5)
407					sm_syslog(LOG_WARNING, NOQID,
408						  "ERROR: DNS TXT record size=%d <= text len=%d",
409						  size, txtlen);
410				goto error;
411			}
412			(*rr)->rr_u.rr_txt = (char *) sm_malloc(txtlen + 1);
413			if ((*rr)->rr_u.rr_txt == NULL)
414				goto error;
415			(void) sm_strlcpy((*rr)->rr_u.rr_txt, (char*) p + 1,
416					  txtlen + 1);
417			break;
418
419#  ifdef T_TLSA
420		  case T_TLSA:
421			if (tTd(8, 61))
422				sm_dprintf("parse_dns_reply: TLSA, size=%d, flags=%X\n",
423					size, flags);
424			if ((flags & RR_AS_TEXT) != 0)
425			{
426				txtlen = bin2hex((char **)&((*rr)->rr_u.rr_data),
427						p, size, 4);
428				if (txtlen <= 0)
429					goto error;
430				break;
431			}
432			/* FALLTHROUGH */
433			/* return "raw" data for caller to use as it pleases */
434#  endif /* T_TLSA */
435
436		  default:
437			(*rr)->rr_u.rr_data = (unsigned char*) sm_malloc(size);
438			if ((*rr)->rr_u.rr_data == NULL)
439				goto error;
440			(void) memcpy((*rr)->rr_u.rr_data, p, size);
441			if (tTd(8, 61) && type == T_A)
442			{
443				SOCKADDR addr;
444
445				(void) memcpy((void *)&addr.sin.sin_addr.s_addr, p, size);
446				sm_dprintf("parse_dns_reply: IPv4=%s\n",
447					inet_ntoa(addr.sin.sin_addr));
448			}
449			break;
450		}
451		p += size;
452		rr = &(*rr)->rr_next;
453	}
454	*rr = NULL;
455	return dr;
456
457  error:
458	dns_free_data(dr);
459	return NULL;
460}
461
462#  if DNSSEC_TEST
463
464#include <arpa/nameser.h>
465
466static int gen_dns_reply __P((unsigned char *, int, unsigned char *,
467		const char *, int, const char *, int, int, int, int,
468		const char *, int, int, int));
469static int dnscrtrr __P((const char *, const char *, int, char *, int,
470	unsigned int, int *, int *, unsigned char *, int,  unsigned char *));
471
472/*
473**  HERRNO2TXT -- return error text for h_errno
474**
475**	Parameters:
476**		e -- h_errno
477**
478**	Returns:
479**		DNS error text if available
480*/
481
482const char *
483herrno2txt(e)
484	int e;
485{
486	switch (e)
487	{
488	  case NETDB_INTERNAL:
489		return "see errno";
490	  case NETDB_SUCCESS:
491		return "OK";
492	  case HOST_NOT_FOUND:
493		return "HOST_NOT_FOUND";
494	  case TRY_AGAIN:
495		return "TRY_AGAIN";
496	  case NO_RECOVERY:
497		return "NO_RECOVERY";
498	  case NO_DATA:
499		return "NO_DATA";
500	}
501	return "bogus h_errno";
502}
503
504/*
505**  GEN_DNS_REPLY -- generate DNS reply data.
506**
507**	Parameters:
508**		buf -- buffer to which DNS data is written
509**		buflen -- length of buffer
510**		bufpos -- position in buffer where DNS RRs are appended
511**		query -- name of query
512**		qtype -- resource record type of query
513**		domain -- name of domain which has been "found"
514**		class -- resource record class
515**		type -- resource record type
516**		ttl -- TTL
517**		size -- size of data
518**		data -- data
519**		txtlen -- length of text
520**		pref -- MX preference
521**		ad -- ad flag
522**
523**	Returns:
524**		>0 length of buffer that has been used.
525**		<0 error
526*/
527
528static int
529gen_dns_reply(buf, buflen, bufpos, query, qtype, domain, class, type, ttl, size, data, txtlen, pref, ad)
530	unsigned char *buf;
531	int buflen;
532	unsigned char *bufpos;
533	const char *query;
534	int qtype;
535	const char *domain;
536	int class;
537	int type;
538	int ttl;
539	int size;
540	const char *data;
541	int txtlen;
542	int pref;
543	int ad;
544{
545	unsigned short ans_cnt;
546	HEADER *hp;
547	unsigned char *cp, *ep;
548	int n;
549	static unsigned char *dnptrs[20], **dpp, **lastdnptr;
550
551	SM_REQUIRE(NULL != buf);
552	SM_REQUIRE(buflen >= HFIXEDSZ);
553	SM_REQUIRE(query != NULL);
554	hp = (HEADER *) buf;
555	ep = buf + buflen;
556	cp = buf + HFIXEDSZ;
557
558	if (bufpos != NULL)
559		cp = bufpos;
560	else
561	{
562		sm_dprintf("gen_dns_reply: query=%s, domain=%s, type=%s, size=%d, ad=%d\n",
563			query, domain, dns_type_to_string(type), size, ad);
564		dpp = dnptrs;
565		*dpp++ = buf;
566		*dpp++ = NULL;
567		lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
568
569		memset(buf, 0, HFIXEDSZ);
570		hp->id = 0xdead;	/* HACK */
571		hp->qr = 1;
572		hp->opcode = QUERY;
573		hp->rd = 0;	/* recursion desired? */
574		hp->rcode = 0; /* !!! */
575		/* hp->aa = ?;	* !!! */
576		/* hp->tc = ?;	* !!! */
577		/* hp->ra = ?;	* !!! */
578		hp->qdcount = htons(1);
579		hp->ancount = 0;
580
581		n = dn_comp(query, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
582		if (n < 0)
583			return n;
584		cp += n;
585		PUTSHORT(qtype, cp);
586		PUTSHORT(class, cp);
587	}
588	hp->ad = ad;
589
590	if (ep - cp < QFIXEDSZ)
591		return (-1);
592	n = dn_comp(domain, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
593	if (n < 0)
594		return n;
595	cp += n;
596	PUTSHORT(type, cp);
597	PUTSHORT(class, cp);
598	PUTLONG(ttl, cp);
599
600	ans_cnt = ntohs((unsigned short) hp->ancount);
601	++ans_cnt;
602	hp->ancount = htons((unsigned short) ans_cnt);
603
604	switch (type)
605	{
606	  case T_MX:
607		n = dn_comp(data, cp + 4, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
608		if (n < 0)
609			return n;
610		PUTSHORT(n + 2, cp);
611		PUTSHORT(pref, cp);
612		cp += n;
613		break;
614
615	  case T_TXT:
616		if (txtlen >= size)
617			return -1;
618		PUTSHORT(txtlen, cp);
619		(void) sm_strlcpy((char *)cp, data, txtlen + 1);
620		cp += txtlen;
621		break;
622
623	  case T_CNAME:
624		n = dn_comp(data, cp + 2, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
625		if (n < 0)
626			return n;
627		PUTSHORT(n, cp);
628		cp += n;
629		break;
630
631#   if defined(T_TLSA)
632	  case T_TLSA:
633		{
634		char *tlsa;
635
636		tlsa = hex2bin(data, size);
637		if (tlsa == NULL)
638			return (-1);
639		n = size / 2;
640		PUTSHORT(n, cp);
641		(void) memcpy(cp, tlsa, n);
642		cp += n;
643		}
644		break;
645#   endif /* T_TLSA */
646
647	  default:
648		PUTSHORT(size, cp);
649		(void) memcpy(cp, data, size);
650		cp += size;
651		break;
652	}
653
654	return (cp - buf);
655}
656
657/*
658**  SETHERRNOFROMSTRING -- set h_errno based on text
659**
660**	Parameters:
661**		str -- string which might contain h_errno text
662**		prc -- pointer to rcode (EX_*)
663**
664**	Returns:
665**		h_errno if found
666**		0 otherwise
667*/
668
669int
670setherrnofromstring(str, prc)
671	const char *str;
672	int *prc;
673{
674	SM_SET_H_ERRNO(0);
675	if (str == NULL || *str == '\0')
676		return 0;
677	if (strstr(str, "herrno:") == NULL)
678		return 0;
679	if (prc != NULL)
680		*prc = EX_NOHOST;
681	if (strstr(str, "host_not_found"))
682		SM_SET_H_ERRNO(HOST_NOT_FOUND);
683	else if (strstr(str, "try_again"))
684	{
685		SM_SET_H_ERRNO(TRY_AGAIN);
686		if (prc != NULL)
687			*prc = EX_TEMPFAIL;
688	}
689	else if (strstr(str, "no_recovery"))
690		SM_SET_H_ERRNO(NO_RECOVERY);
691	else if (strstr(str, "no_data"))
692		SM_SET_H_ERRNO(NO_DATA);
693	else
694		SM_SET_H_ERRNO(NETDB_INTERNAL);
695	return h_errno;
696}
697
698/*
699**  GETTTLFROMSTRING -- extract ttl from a string
700**
701**	Parameters:
702**		str -- string which might contain ttl
703**
704**	Returns:
705**		ttl if found
706**		0 otherwise
707*/
708
709int
710getttlfromstring(str)
711	const char *str;
712{
713	if (str == NULL || *str == '\0')
714		return 0;
715#define TTL_PRE "ttl="
716	if (strstr(str, TTL_PRE) == NULL)
717		return 0;
718	return strtoul(str + strlen(TTL_PRE), NULL, 10);
719}
720
721/*
722**  NSPORTIP -- parse port@IPv4 and set NS accordingly
723**
724**	Parameters:
725**		p -- port@Ipv4
726**
727**	Returns:
728**		<0: error
729**		>0: ok
730**
731**	Side Effects:
732**		sets NS for DNS lookups
733*/
734
735/*
736**  There should be a generic function for this...
737**  milter_open(), socket_map_open(), others?
738*/
739
740int
741nsportip(p)
742	char *p;
743{
744	char *h;
745	int r;
746	unsigned short port;
747	struct in_addr nsip;
748
749	if (p == NULL || *p == '\0')
750		return -1;
751
752	port = 0;
753	while (SM_ISSPACE(*p))
754		p++;
755	if (*p == '\0')
756		return -1;
757	h = strchr(p, '@');
758	if (h != NULL)
759	{
760		*h = '\0';
761		if (isascii(*p) && isdigit(*p))
762			port = atoi(p);
763		*h = '@';
764		p = h + 1;
765	}
766	h = strchr(p, ' ');
767	if (h != NULL)
768		*h = '\0';
769	r = inet_pton(AF_INET, p, &nsip);
770	if (r > 0)
771	{
772		if ((_res.options & RES_INIT) == 0)
773			(void) res_init();
774		dns_setns(&nsip, port);
775	}
776	if (h != NULL)
777		*h = ' ';
778	return r > 0 ? 0 : -1;
779}
780
781/*
782**  DNS_SETNS -- set one NS in resolver context
783**
784**	Parameters:
785**		ns -- (IPv4 address of) nameserver
786**		port -- nameserver port
787**
788**	Returns:
789**		None.
790*/
791
792void
793dns_setns(ns, port)
794	struct in_addr *ns;
795	unsigned int port;
796{
797	_res.nsaddr_list[0].sin_family = AF_INET;
798	_res.nsaddr_list[0].sin_addr = *ns;
799	if (port != 0)
800		_res.nsaddr_list[0].sin_port = htons(port);
801	_res.nscount = 1;
802	if (tTd(8, 61))
803		sm_dprintf("dns_setns(%s,%u)\n", inet_ntoa(*ns), port);
804}
805
806#   if defined(T_TLSA)
807/*
808**  HEX2BIN -- convert hex string to binary TLSA RR
809**
810**	Parameters:
811**		p --  hex representation of TLSA RR
812**		size -- length of p
813**
814**	Returns:
815**		pointer to binary TLSA RR
816**		NULL: error
817*/
818
819static char *
820hex2bin(p, size)
821	const char *p;
822	int size;
823{
824	int i, pos, txtlen;
825	char *tlsa;
826
827	txtlen = size / 2;
828	if (txtlen * 2 == size)
829	{
830		if (LogLevel > 5)
831			sm_syslog(LOG_WARNING, NOQID,
832				  "ERROR: hex2bin: size %d wrong", size);
833		return NULL;
834	}
835	tlsa = sm_malloc(txtlen + 1);
836	if (tlsa == NULL)
837	{
838		if (tTd(8, 17))
839			sm_dprintf("len=%d, tlsa=NULL\n", txtlen);
840		return NULL;
841	}
842
843#define CHAR2INT(c)	(((c) <= '9') ? ((c) - '0') : (toupper(c) - 'A' + 10))
844	for (i = 0, pos = 0; i + 1 < size && pos < txtlen; i += 2, pos++)
845		tlsa[pos] = CHAR2INT(p[i]) * 16 + CHAR2INT(p[i+1]);
846
847	return tlsa;
848}
849#   endif /* T_TLSA */
850
851const char *
852rr_type2tag(rr_type)
853	int rr_type;
854{
855	switch (rr_type)
856	{
857	  case T_A:
858		return "ipv4";
859#   if NETINET6
860	  case T_AAAA:
861		return "ipv6";
862#   endif
863	  case T_CNAME:
864		return "cname";
865	  case T_MX:
866		return "mx";
867#   ifdef T_TLSA
868	  case T_TLSA:
869		return "tlsa";
870#   endif
871	}
872	return NULL;
873}
874
875/*
876**  DNSCRTRR -- create DNS RR
877**
878**	Parameters:
879**		domain -- original query domain
880**		query -- name of query
881**		qtype -- resource record type of query
882**		value -- (list of) data to set
883**		rr_type -- resource record type
884**		flags -- flags how to handle various lookups
885**		herr -- (pointer to) h_errno (output if non-NULL)
886**		adp -- (pointer to) ad flag
887**		answer -- buffer for RRs
888**		anslen -- size of answer
889**		anspos -- current position in answer
890**
891**	Returns:
892**		>0: length of data in answer
893**		<0: error, check *herr
894*/
895
896static int
897dnscrtrr(domain, query, qtype, value, rr_type, flags, herr, adp, answer, anslen, anspos)
898	const char *domain;
899	const char *query;
900	int qtype;
901	char *value;
902	int rr_type;
903	unsigned int flags;
904	int *herr;
905	int *adp;
906	unsigned char *answer;
907	int anslen;
908	unsigned char *anspos;
909{
910	SOCKADDR addr;
911	int ttl, ad, rlen;
912	char *p, *token;
913	char data[IN6ADDRSZ];
914	char rhs[MAXLINE];
915
916	rlen = -1;
917	if (NULL == value || '\0' == *value)
918		return rlen;
919	SM_REQUIRE(adp != NULL);
920	(void) sm_strlcpy(rhs, value, sizeof(rhs));
921	p = rhs;
922	if (setherrnofromstring(p, NULL) != 0)
923	{
924		if (herr != NULL)
925			*herr = h_errno;
926		if (tTd(8, 16))
927			sm_dprintf("dnscrtrr rhs=%s h_errno=%d (%s)\n",
928				p, h_errno, herrno2txt(h_errno));
929		return rlen;
930	}
931
932	ttl = 0;
933	ad = 0;
934	for (token = p; token != NULL && *token != '\0'; token = p)
935	{
936		rlen = 0;
937		while (p != NULL && *p != '\0' && !SM_ISSPACE(*p))
938			++p;
939		if (SM_ISSPACE(*p))
940			*p++ = '\0';
941		sm_dprintf("dnscrtrr: token=%s\n", token);
942		if (strcmp(token, "ad") == 0)
943		{
944			bool adflag;
945
946			adflag = (_res.options & RES_USE_DNSSEC) != 0;
947
948			/* maybe print this only for the final RR? */
949			if (tTd(8, 61))
950				sm_dprintf("dnscrtrr: ad=1, adp=%d, adflag=%d\n",
951					*adp, adflag);
952			if (*adp != 0 && adflag)
953			{
954				*adp = 1;
955				ad = 1;
956			}
957			continue;
958		}
959		if (ttl == 0 && (ttl = getttlfromstring(token)) > 0)
960		{
961			if (tTd(8, 61))
962				sm_dprintf("dnscrtrr: ttl=%d\n", ttl);
963			continue;
964		}
965
966		if (rr_type == T_A)
967		{
968			addr.sin.sin_addr.s_addr = inet_addr(token);
969			(void) memmove(data, (void *)&addr.sin.sin_addr.s_addr,
970				INADDRSZ);
971			rlen = gen_dns_reply(answer, anslen, anspos,
972				query, qtype, domain, C_IN, rr_type, ttl,
973				INADDRSZ, data, 0, 0, ad);
974		}
975
976#   if NETINET6
977		if (rr_type == T_AAAA)
978		{
979			anynet_pton(AF_INET6, token, &addr.sin6.sin6_addr);
980			memmove(data, (void *)&addr.sin6.sin6_addr, IN6ADDRSZ);
981			rlen = gen_dns_reply(answer, anslen, anspos,
982				query, qtype, domain, C_IN, rr_type, ttl,
983				IN6ADDRSZ, data, 0, 0, ad);
984		}
985#   endif /* NETINET6 */
986
987		if (rr_type == T_MX)
988		{
989			char *endptr;
990			int pref;
991
992			pref = (int) strtoul(token, &endptr, 10);
993			if (endptr == NULL || *endptr != ':')
994				goto error;
995			token = endptr + 1;
996			rlen = gen_dns_reply(answer, anslen, anspos,
997				query, qtype, domain, C_IN, rr_type, ttl,
998				strlen(token) + 1, token, 0, pref, ad);
999			if (tTd(8, 50))
1000				sm_dprintf("dnscrtrr: mx=%s, pref=%d\n",
1001					token, pref);
1002		}
1003
1004#   ifdef T_TLSA
1005		if (rr_type == T_TLSA)
1006			rlen = gen_dns_reply(answer, anslen, anspos,
1007				query, qtype, domain, C_IN, rr_type, ttl,
1008				strlen(token) + 1, token, 0, 0, ad);
1009#   endif
1010
1011		if (rr_type == T_CNAME)
1012			rlen = gen_dns_reply(answer, anslen, anspos,
1013				query, qtype, domain, C_IN, rr_type, ttl,
1014				strlen(token), token, 0, 0, ad);
1015		if (rlen < 0)
1016			goto error;
1017		if (rlen > 0)
1018			anspos = answer + rlen;
1019	}
1020
1021	if (ad != 1)
1022		*adp = 0;
1023
1024	return rlen;
1025
1026  error:
1027	if (herr != NULL && 0 == *herr)
1028		*herr = NO_RECOVERY;
1029	return -1;
1030}
1031
1032/*
1033**  TSTDNS_SEARCH -- replacement for res_search() for testing
1034**
1035**	Parameters:
1036**		domain -- query domain
1037**		class -- class
1038**		type -- resource record type
1039**		answer -- buffer for RRs
1040**		anslen -- size of answer
1041**
1042**	Returns:
1043**		>0: length of data in answer
1044**		<0: error, check h_errno
1045*/
1046
1047int
1048tstdns_search(domain, class, type, answer, anslen)
1049	const char *domain;
1050	int class;
1051	int type;
1052	unsigned char *answer;
1053	int anslen;
1054{
1055	int rlen, ad, maprcode, cnt, flags, herr;
1056	bool found_cname;
1057	const char *query;
1058	char *p;
1059	const char *tag;
1060	char *av[2];
1061	STAB *map;
1062	char key[MAXNAME + 16];
1063	char rhs[MAXLINE];
1064	unsigned char *anspos;
1065
1066	rlen = -1;
1067	herr = 0;
1068	if (class != C_IN)
1069		goto error;
1070	if (NULL == domain || '\0' == *domain)
1071		goto error;
1072	tag = rr_type2tag(type);
1073	if (tag == NULL)
1074		goto error;
1075	maprcode = EX_OK;
1076	ad = -1;
1077	flags = 0;
1078	query = domain;
1079	anspos = NULL;
1080
1081	map = stab("access", ST_MAP, ST_FIND);
1082	if (NULL == map)
1083	{
1084		sm_dprintf("access map not found\n");
1085		goto error;
1086	}
1087	if (!bitset(MF_OPEN, map->s_map.map_mflags) &&
1088	    !openmap(&(map->s_map)))
1089	{
1090		sm_dprintf("access map open failed\n");
1091		goto error;
1092	}
1093
1094/*
1095**  Look up tag:domain, if not found and domain does not end with a dot
1096**  (and the proper debug level is selected), also try with trailing dot.
1097*/
1098
1099#define SM_LOOKUP2(tag)	\
1100	do {	\
1101		int len;	\
1102				\
1103		len = strlen(domain);	\
1104		av[0] = key;	\
1105		av[1] = NULL;	\
1106		snprintf(key, sizeof(key), "%s:%s", tag, domain); \
1107		p = (*map->s_map.map_class->map_lookup)(&map->s_map, key, av, \
1108			&maprcode);	\
1109		if (p != NULL)	\
1110			break;	\
1111		if (!tTd(8, 112) || (len > 0 && '.' == domain[len - 1])) \
1112			break;	\
1113		snprintf(key, sizeof(key), "%s:%s.", tag, domain); \
1114		p = (*map->s_map.map_class->map_lookup)(&map->s_map, key, av, \
1115			&maprcode);	\
1116	} while (0)
1117
1118	cnt = 0;
1119	found_cname = false;
1120	while (cnt < 6)
1121	{
1122		char *last;
1123
1124		/* Should this try with/without trailing dot? */
1125		SM_LOOKUP2(tag);
1126		if (p != NULL)
1127		{
1128			sm_dprintf("access map lookup key=%s, value=%s\n", key,
1129				p);
1130			break;
1131		}
1132		if (NULL == p && (flags & RR_NO_CNAME) == 0)
1133		{
1134			sm_dprintf("access map lookup failed key=%s, try cname\n",
1135				key);
1136			SM_LOOKUP2("cname");
1137			if (p != NULL)
1138			{
1139				sm_dprintf("cname lookup key=%s, value=%s, ad=%d\n",
1140					key, p, ad);
1141				rlen = dnscrtrr(domain, query, type, p, T_CNAME,
1142						flags, &herr, &ad, answer,
1143						anslen, anspos);
1144				if (rlen < 0)
1145					goto error;
1146				if (rlen > 0)
1147					anspos = answer + rlen;
1148				found_cname = true;
1149			}
1150		}
1151		if (NULL == p)
1152			break;
1153
1154		(void) sm_strlcpy(rhs, p, sizeof(rhs));
1155		p = rhs;
1156
1157		/* skip (leading) ad/ttl: look for last ' ' */
1158		if ((last = strrchr(p, ' ')) != NULL && last[1] != '\0')
1159			domain = last + 1;
1160		else
1161			domain = p;
1162		++cnt;
1163	}
1164	if (NULL == p)
1165	{
1166		int t;
1167		char *tags[] = { "ipv4", "mx", "tlsa",
1168#   if NETINET6
1169			"ipv6",
1170#   endif
1171			NULL
1172		};
1173
1174		for (t = 0; tags[t] != NULL; t++)
1175		{
1176			if (strcmp(tag, tags[t]) == 0)
1177				continue;
1178			SM_LOOKUP2(tags[t]);
1179			if (p != NULL)
1180			{
1181				sm_dprintf("access map lookup failed key=%s:%s, but found key=%s\n",
1182					tag, domain, key);
1183				herr = NO_DATA;
1184				goto error;
1185			}
1186		}
1187		sm_dprintf("access map lookup failed key=%s\n", key);
1188		herr = HOST_NOT_FOUND;
1189		goto error;
1190	}
1191	if (found_cname && (flags & RR_ONLY_CNAME) != 0)
1192		return rlen;
1193	rlen = dnscrtrr(domain,  query, type, p, type, flags, &herr, &ad,
1194			answer, anslen, anspos);
1195	if (rlen < 0)
1196		goto error;
1197	return rlen;
1198
1199  error:
1200	if (0 == herr)
1201		herr = NO_RECOVERY;
1202	SM_SET_H_ERRNO(herr);
1203	sm_dprintf("rlen=%d, herr=%d\n", rlen, herr);
1204	return -1;
1205}
1206
1207/*
1208**  TSTDNS_QUERYDOMAIN -- replacement for res_querydomain() for testing
1209**
1210**	Parameters:
1211**		name -- query name
1212**		domain -- query domain
1213**		class -- class
1214**		type -- resource record type
1215**		answer -- buffer for RRs
1216**		anslen -- size of answer
1217**
1218**	Returns:
1219**		>0: length of data in answer
1220**		<0: error, check h_errno
1221*/
1222
1223int
1224tstdns_querydomain(name, domain, class, type, answer, anslen)
1225	const char *name;
1226	const char *domain;
1227	int class;
1228	int type;
1229	unsigned char *answer;
1230	int anslen;
1231{
1232	char query[MAXNAME];
1233	int len;
1234
1235	if (NULL == name)
1236		goto error;
1237	if (NULL == domain || '\0' == *domain)
1238		return tstdns_search(name, class, type, answer, anslen);
1239
1240	len = snprintf(query, sizeof(query), "%s.%s", name, domain);
1241	if (len >= (int)sizeof(query))
1242		goto error;
1243	return tstdns_search(query, class, type, answer, anslen);
1244
1245  error:
1246	SM_SET_H_ERRNO(NO_RECOVERY);
1247	return -1;
1248}
1249
1250#  endif /* DNSSEC_TEST */
1251
1252/*
1253**  DNS_LOOKUP_INT -- perform DNS lookup
1254**
1255**	Parameters:
1256**		domain -- name to lookup
1257**		rr_class -- resource record class
1258**		rr_type -- resource record type
1259**		retrans -- retransmission timeout
1260**		retry -- number of retries
1261**		options -- DNS resolver options
1262**		flags -- currently only passed to parse_dns_reply()
1263**		err -- (pointer to) errno (output if non-NULL)
1264**		herr -- (pointer to) h_errno (output if non-NULL)
1265**
1266**	Returns:
1267**		result of lookup if succeeded.
1268**		NULL otherwise.
1269*/
1270
1271DNS_REPLY_T *
1272dns_lookup_int(domain, rr_class, rr_type, retrans, retry, options, flags, err, herr)
1273	const char *domain;
1274	int rr_class;
1275	int rr_type;
1276	time_t retrans;
1277	int retry;
1278	unsigned int options;
1279	unsigned int flags;
1280	int *err;
1281	int *herr;
1282{
1283	int len;
1284	unsigned long old_options = 0;
1285	time_t save_retrans = 0;
1286	int save_retry = 0;
1287	DNS_REPLY_T *dr = NULL;
1288	querybuf reply_buf;
1289	unsigned char *reply;
1290	int (*resfunc) __P((const char *, int, int, u_char *, int));
1291
1292#  define SMRBSIZE ((int) sizeof(reply_buf))
1293#  ifndef IP_MAXPACKET
1294#   define IP_MAXPACKET	65535
1295#  endif
1296
1297	resfunc = res_search;
1298#  if DNSSEC_TEST
1299	if (tTd(8, 110))
1300		resfunc = tstdns_search;
1301#  endif
1302
1303	old_options = _res.options;
1304	_res.options |= options;
1305	if (err != NULL)
1306		*err = 0;
1307	if (herr != NULL)
1308		*herr = 0;
1309	if (tTd(8, 16))
1310	{
1311		_res.options |= RES_DEBUG;
1312		sm_dprintf("dns_lookup_int(%s, %d, %s, %x)\n", domain,
1313			   rr_class, dns_type_to_string(rr_type), options);
1314	}
1315#  if DNSSEC_TEST
1316	if (tTd(8, 15))
1317		sm_dprintf("NS=%s, port=%d\n",
1318			inet_ntoa(_res.nsaddr_list[0].sin_addr),
1319			ntohs(_res.nsaddr_list[0].sin_port));
1320#  endif
1321	if (retrans > 0)
1322	{
1323		save_retrans = _res.retrans;
1324		_res.retrans = retrans;
1325	}
1326	if (retry > 0)
1327	{
1328		save_retry = _res.retry;
1329		_res.retry = retry;
1330	}
1331	errno = 0;
1332	SM_SET_H_ERRNO(0);
1333	reply = (unsigned char *)&reply_buf;
1334	len = (*resfunc)(domain, rr_class, rr_type, reply, SMRBSIZE);
1335	if (len >= SMRBSIZE)
1336	{
1337		if (len >= IP_MAXPACKET)
1338		{
1339			if (tTd(8, 4))
1340				sm_dprintf("dns_lookup: domain=%s, length=%d, default_size=%d, max=%d, status=response too long\n",
1341					   domain, len, SMRBSIZE, IP_MAXPACKET);
1342		}
1343		else
1344		{
1345			if (tTd(8, 6))
1346				sm_dprintf("dns_lookup: domain=%s, length=%d, default_size=%d, max=%d, status=response longer than default size, resizing\n",
1347					   domain, len, SMRBSIZE, IP_MAXPACKET);
1348			reply = (unsigned char *)sm_malloc(IP_MAXPACKET);
1349			if (reply == NULL)
1350				SM_SET_H_ERRNO(TRY_AGAIN);
1351			else
1352			{
1353				SM_SET_H_ERRNO(0);
1354				len = (*resfunc)(domain, rr_class, rr_type,
1355						 reply, IP_MAXPACKET);
1356			}
1357		}
1358	}
1359	_res.options = old_options;
1360	if (len < 0)
1361	{
1362		if (err != NULL)
1363			*err = errno;
1364		if (herr != NULL)
1365			*herr = h_errno;
1366		if (tTd(8, 16))
1367		{
1368			sm_dprintf("dns_lookup_int(%s, %d, %s, %x)=%d, errno=%d, h_errno=%d"
1369#  if DNSSEC_TEST
1370				" (%s)"
1371#  endif
1372				"\n",
1373				domain, rr_class, dns_type_to_string(rr_type),
1374				options, len, errno, h_errno
1375#  if DNSSEC_TEST
1376				, herrno2txt(h_errno)
1377#  endif
1378				);
1379		}
1380	}
1381	else if (tTd(8, 16))
1382	{
1383		sm_dprintf("dns_lookup_int(%s, %d, %s, %x)=%d\n",
1384			domain, rr_class, dns_type_to_string(rr_type),
1385			options, len);
1386	}
1387	if (len >= 0 && len < IP_MAXPACKET && reply != NULL)
1388		dr = parse_dns_reply(reply, len, flags);
1389	if (reply != (unsigned char *)&reply_buf && reply != NULL)
1390	{
1391		sm_free(reply);
1392		reply = NULL;
1393	}
1394	if (retrans > 0)
1395		_res.retrans = save_retrans;
1396	if (retry > 0)
1397		_res.retry = save_retry;
1398	return dr;
1399}
1400
1401/*
1402**  DNS_LOOKUP_MAP -- perform DNS map lookup
1403**
1404**	Parameters:
1405**		domain -- name to lookup
1406**		rr_class -- resource record class
1407**		rr_type -- resource record type
1408**		retrans -- retransmission timeout
1409**		retry -- number of retries
1410**		options -- DNS resolver options
1411**
1412**	Returns:
1413**		result of lookup if succeeded.
1414**		NULL otherwise.
1415*/
1416
1417DNS_REPLY_T *
1418dns_lookup_map(domain, rr_class, rr_type, retrans, retry, options)
1419	const char *domain;
1420	int rr_class;
1421	int rr_type;
1422	time_t retrans;
1423	int retry;
1424	unsigned int options;
1425{
1426	return dns_lookup_int(domain, rr_class, rr_type, retrans, retry,
1427			options, RR_AS_TEXT, NULL, NULL);
1428}
1429
1430#  if DANE
1431/*
1432**  DNS2HE -- convert DNS_REPLY_T list to hostent struct
1433**
1434**	Parameters:
1435**		dr -- DNS lookup result
1436**		family -- address family
1437**
1438**	Returns:
1439**		hostent struct if succeeded.
1440**		NULL otherwise.
1441**
1442**	Note:
1443**		this returns a pointer to a static struct!
1444*/
1445
1446struct hostent *
1447dns2he(dr, family)
1448	DNS_REPLY_T *dr;
1449	int family;
1450{
1451#   define SM_MAX_ADDRS	256
1452	static struct hostent he;
1453	static char *he_aliases[1];
1454	static char *he_addr_list[SM_MAX_ADDRS];
1455#   ifdef IN6ADDRSZ
1456#    define IN_ADDRSZ IN6ADDRSZ
1457#   else
1458#    define IN_ADDRSZ INADDRSZ
1459#   endif
1460	static char he_addrs[SM_MAX_ADDRS * IN_ADDRSZ];
1461	static char he_name[MAXNAME];
1462	static bool he_init = false;
1463	struct hostent *h;
1464	struct in_addr ia;
1465	int i;
1466	size_t sz;
1467#   if NETINET6 && DNSSEC_TEST
1468	struct in6_addr ia6;
1469	char buf6[INET6_ADDRSTRLEN];
1470#   endif
1471	RESOURCE_RECORD_T *rr;
1472
1473	if (dr == NULL)
1474		return NULL;
1475
1476	h = &he;
1477	if (!he_init)
1478	{
1479		he_aliases[0] = NULL;
1480		he.h_aliases = he_aliases;
1481		he.h_addr_list = he_addr_list;
1482		he.h_name = he_name;
1483		he_init = true;
1484	}
1485	h->h_addrtype = family;
1486
1487	if (tTd(8, 17))
1488		sm_dprintf("dns2he: ad=%d\n", dr->dns_r_h.ad);
1489
1490	/* do we want/need to copy the name? */
1491	rr = dr->dns_r_head;
1492	if (rr != NULL && rr->rr_domain != NULL)
1493		sm_strlcpy(h->h_name, rr->rr_domain, sizeof(he_name));
1494	else
1495		h->h_name[0] = '\0';
1496
1497	sz = 0;
1498#   if NETINET
1499	if (family == AF_INET)
1500		sz = INADDRSZ;
1501#   endif
1502#   if NETINET6
1503	if (family == AF_INET6)
1504		sz = IN6ADDRSZ;
1505#   endif
1506	if (sz == 0)
1507		return NULL;
1508	h->h_length = sz;
1509
1510	for (rr = dr->dns_r_head, i = 0; rr != NULL && i < SM_MAX_ADDRS - 1;
1511	     rr = rr->rr_next)
1512	{
1513		h->h_addr_list[i] = he_addrs + i * h->h_length;
1514		switch (rr->rr_type)
1515		{
1516#   if NETINET
1517		  case T_A:
1518			if (family != AF_INET)
1519				continue;
1520			memmove(h->h_addr_list[i], rr->rr_u.rr_a, INADDRSZ);
1521			++i;
1522			break;
1523#   endif /* NETINET */
1524#   if NETINET6
1525		  case T_AAAA:
1526			if (family != AF_INET6)
1527				continue;
1528			memmove(h->h_addr_list[i], rr->rr_u.rr_aaaa, IN6ADDRSZ);
1529			++i;
1530			break;
1531#   endif /* NETINET6 */
1532		  case T_CNAME:
1533#   if DNSSEC_TEST
1534			if (tTd(8, 16))
1535				sm_dprintf("dns2he: cname: %s ttl=%d\n",
1536					rr->rr_u.rr_txt, rr->rr_ttl);
1537#   endif
1538			break;
1539		  case T_MX:
1540#   if DNSSEC_TEST
1541			if (tTd(8, 16))
1542				sm_dprintf("dns2he: mx: %d %s ttl=%d\n",
1543					rr->rr_u.rr_mx->mx_r_preference,
1544					rr->rr_u.rr_mx->mx_r_domain,
1545					rr->rr_ttl);
1546#   endif
1547			break;
1548
1549#   if defined(T_TLSA)
1550		  case T_TLSA:
1551#    if DNSSEC_TEST
1552			if (tTd(8, 16))
1553			{
1554				char *tlsa;
1555				int len;
1556
1557				len = bin2hex(&tlsa, rr->rr_u.rr_data,
1558						rr->rr_size, 4);
1559				if (len > 0)
1560					sm_dprintf("dns2he: tlsa: %s ttl=%d\n",
1561						tlsa, rr->rr_ttl);
1562			}
1563#    endif
1564			break;
1565#   endif /* T_TLSA */
1566		}
1567	}
1568
1569	/* complain if list is too long! */
1570	SM_ASSERT(i < SM_MAX_ADDRS);
1571	h->h_addr_list[i] = NULL;
1572
1573#   if DNSSEC_TEST
1574	if (tTd(8, 16))
1575	{
1576		for (i = 0; h->h_addr_list[i] != NULL && i < SM_MAX_ADDRS; i++)
1577		{
1578			char *addr;
1579
1580			addr = NULL;
1581#    if NETINET6
1582			if (h->h_addrtype == AF_INET6)
1583			{
1584				memmove(&ia6, h->h_addr_list[i], IN6ADDRSZ);
1585				addr = anynet_ntop(&ia6, buf6, sizeof(buf6));
1586			}
1587			else
1588#    endif /* NETINET6 */
1589			/* "else" in #if code above */
1590			{
1591				memmove(&ia, h->h_addr_list[i], INADDRSZ);
1592				addr = (char *) inet_ntoa(ia);
1593			}
1594			if (addr != NULL)
1595				sm_dprintf("dns2he: addr[%d]: %s\n", i, addr);
1596		}
1597	}
1598#   endif /* DNSSEC_TEST */
1599	return h;
1600}
1601#  endif /* DANE */
1602# endif /* NAMED_BIND */
1603#endif /* DNSMAP || DANE */
1604