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