]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/src/sm_resolve.c
MFC: Merge sendmail 8.16.1 to HEAD: See contrib/sendmail/RELEASE_NOTES for
[FreeBSD/FreeBSD.git] / contrib / sendmail / src / sm_resolve.c
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
56 SM_RCSID("$Id: sm_resolve.c,v 8.40 2013-11-22 20:51:56 ca Exp $")
57
58 static 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
91 static DNS_REPLY_T *parse_dns_reply __P((unsigned char *, int, unsigned int));
92 #  if DNSSEC_TEST && defined(T_TLSA)
93 static 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
107 int
108 dns_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
130 const char *
131 dns_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
152 void
153 dns_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
190 static int bin2hex __P((char **, unsigned char *, int, int));
191
192 static int
193 bin2hex(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
244 static DNS_REPLY_T *
245 parse_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
466 static 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));
469 static 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
482 const char *
483 herrno2txt(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
528 static int
529 gen_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
669 int
670 setherrnofromstring(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
709 int
710 getttlfromstring(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
740 int
741 nsportip(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
792 void
793 dns_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
819 static char *
820 hex2bin(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
851 const char *
852 rr_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
896 static int
897 dnscrtrr(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
1047 int
1048 tstdns_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
1223 int
1224 tstdns_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
1271 DNS_REPLY_T *
1272 dns_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
1417 DNS_REPLY_T *
1418 dns_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
1446 struct hostent *
1447 dns2he(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 */