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