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