1 /*
2 * Copyright (c) 1998-2004, 2006, 2010 Proofpoint, Inc. and its suppliers.
3 * All rights reserved.
4 * Copyright (c) 1986, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14 #include <sendmail.h>
15 #include "map.h"
16 #if _FFR_EAI
17 #include <unicode/uidna.h>
18 #endif
19
20 #if NAMED_BIND
21 SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (with name server)")
22 #else
23 SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (without name server)")
24 #endif
25
26 #if NAMED_BIND
27
28 # include <arpa/inet.h>
29 # include <sm_resolve.h>
30 # if DANE
31 # include <tls.h>
32 # ifndef SM_NEG_TTL
33 # define SM_NEG_TTL 60 /* "negative" TTL */
34 # endif
35 # endif
36
37
38 # ifndef MXHOSTBUFSIZE
39 # define MXHOSTBUFSIZE (128 * MAXMXHOSTS)
40 # endif
41
42 static char MXHostBuf[MXHOSTBUFSIZE];
43 # if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2)
44 ERROR: _MXHOSTBUFSIZE is out of range
45 # endif
46
47 # ifndef MAXDNSRCH
48 # define MAXDNSRCH 6 /* number of possible domains to search */
49 # endif
50
51 # ifndef RES_DNSRCH_VARIABLE
52 # define RES_DNSRCH_VARIABLE _res.dnsrch
53 # endif
54
55 # ifndef NO_DATA
56 # define NO_DATA NO_ADDRESS
57 # endif
58
59 # ifndef HFIXEDSZ
60 # define HFIXEDSZ 12 /* sizeof(HEADER) */
61 # endif
62
63 # define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */
64
65 # if defined(__RES) && (__RES >= 19940415)
66 # define RES_UNC_T char *
67 # else
68 # define RES_UNC_T unsigned char *
69 # endif
70
71 static int mxrand __P((char *));
72 static int fallbackmxrr __P((int, unsigned short *, char **));
73
74 # if DANE
75
76 /*
77 ** TLSAADD -- add TLSA records to dane_tlsa entry
78 **
79 ** Parameters:
80 ** name -- key for stab entry (for debugging output)
81 ** dr -- DNS reply
82 ** dane_tlsa -- dane_tlsa entry
83 ** dnsrc -- DNS lookup return code (h_errno)
84 ** n -- current number of TLSA records in dane_tlsa entry
85 ** pttl -- (pointer to) TTL (in/out)
86 ** level -- recursion level (CNAMEs)
87 **
88 ** Returns:
89 ** new number of TLSA records
90 */
91
92 static int tlsaadd __P((const char *, DNS_REPLY_T *, dane_tlsa_P, int, int,
93 unsigned int *, int));
94
95 static int
tlsaadd(name,dr,dane_tlsa,dnsrc,n,pttl,level)96 tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
97 const char *name;
98 DNS_REPLY_T *dr;
99 dane_tlsa_P dane_tlsa;
100 int dnsrc;
101 int n;
102 unsigned int *pttl;
103 int level;
104 {
105 RESOURCE_RECORD_T *rr;
106 unsigned int ttl;
107 int nprev;
108
109 if (dnsrc != 0)
110 {
111 if (tTd(8, 2))
112 sm_dprintf("tlsaadd(%s), prev=%d, dnsrc=%d\n",
113 name, dane_tlsa->dane_tlsa_dnsrc, dnsrc);
114
115 /* check previous error and keep the "most important" one? */
116 dane_tlsa->dane_tlsa_dnsrc = dnsrc;
117 # if DNSSEC_TEST
118 if (tTd(8, 110))
119 *pttl = tTdlevel(8)-110; /* how to make this an option? */
120 else
121 # else
122 *pttl = SM_NEG_TTL;
123 # endif
124
125 return n;
126 }
127 if (dr == NULL)
128 return n;
129 if (dr->dns_r_h.ad != 1 && Dane == DANE_SECURE) /* not secure? */
130 return n;
131 ttl = *pttl;
132
133 /* first: try to find TLSA records */
134 nprev = n;
135 for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR;
136 rr = rr->rr_next)
137 {
138 int tlsa_chk;
139
140 if (rr->rr_type != T_TLSA)
141 {
142 if (rr->rr_type != T_CNAME && tTd(8, 8))
143 sm_dprintf("tlsaadd(%s), type=%s\n", name,
144 dns_type_to_string(rr->rr_type));
145 continue;
146 }
147 tlsa_chk = dane_tlsa_chk(rr->rr_u.rr_data, rr->rr_size, name,
148 true);
149 if (!TLSA_IS_VALID(tlsa_chk))
150 continue;
151
152 /*
153 ** To do: the RRs should be sorted (by "complexity") --
154 ** when more than one type is supported.
155 */
156
157 dane_tlsa->dane_tlsa_rr[n] = rr->rr_u.rr_data;
158 dane_tlsa->dane_tlsa_len[n] = rr->rr_size;
159 if (tTd(8, 2))
160 {
161 unsigned char *p;
162
163 p = rr->rr_u.rr_data;
164 sm_dprintf("tlsaadd(%s), n=%d, %d-%d-%d:%02x\n", name,
165 n, (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
166 }
167
168 /* require some minimum TTL? */
169 if (ttl > rr->rr_ttl && rr->rr_ttl > 0)
170 ttl = rr->rr_ttl;
171
172 /* hack: instead of copying the data, just "take it over" */
173 rr->rr_u.rr_data = NULL;
174 ++n;
175 }
176
177 /* second: check for CNAME records, but only if no TLSA RR was added */
178 for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR && nprev == n;
179 rr = rr->rr_next)
180 {
181 DNS_REPLY_T *drc;
182 int err, herr;
183
184 if (rr->rr_type != T_CNAME)
185 continue;
186 if (level > 1)
187 {
188 if (tTd(8, 2))
189 sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d\n",
190 name, rr->rr_u.rr_txt, level);
191 continue;
192 }
193
194 drc = dns_lookup_int(rr->rr_u.rr_txt, C_IN, T_TLSA, 0, 0,
195 (Dane == DANE_SECURE &&
196 !TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX))
197 ? SM_RES_DNSSEC : 0,
198 RR_RAW, &err, &herr);
199
200 if (tTd(8, 2))
201 sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d, dr=%p, ad=%d, err=%d, herr=%d\n",
202 name, rr->rr_u.rr_txt, level,
203 (void *)drc, drc != NULL ? drc->dns_r_h.ad : -1,
204 err, herr);
205 nprev = n = tlsaadd(name, drc, dane_tlsa, herr, n, pttl,
206 level + 1);
207 dns_free_data(drc);
208 drc = NULL;
209 }
210
211 *pttl = ttl;
212 return n;
213 }
214
215 /*
216 ** GETTLSA -- get TLSA records for named host using DNS
217 **
218 ** Parameters:
219 ** host -- host
220 ** name -- name for stab entry key (if NULL: host)
221 ** pste -- (pointer to) stab entry (output)
222 ** flags -- TLSAFL*
223 ** mxttl -- TTL of MX (or host)
224 ** port -- port
225 **
226 ** Returns:
227 ** The number of TLSA records found.
228 ** <0 if there is an internal failure.
229 **
230 ** Side effects:
231 ** Enters TLSA RRs into stab().
232 ** If the DNS lookup fails temporarily, an "empty" entry is
233 ** created with that DNS error code.
234 */
235
236 int
gettlsa(host,name,pste,flags,mxttl,port)237 gettlsa(host, name, pste, flags, mxttl, port)
238 char *host;
239 char *name;
240 STAB **pste;
241 unsigned long flags;
242 unsigned int mxttl;
243 unsigned int port;
244 {
245 DNS_REPLY_T *dr;
246 dane_tlsa_P dane_tlsa;
247 STAB *ste;
248 time_t now;
249 unsigned int ttl;
250 int n_rrs, len, err, herr;
251 bool isrname;
252 char nbuf[MAXDNAME];
253 char key[MAXDNAME];
254
255 SM_REQUIRE(host != NULL);
256 if (pste != NULL)
257 *pste = NULL;
258 if ('\0' == *host)
259 return 0;
260
261 isrname = NULL == name;
262 if (isrname)
263 name = host;
264 now = 0;
265 n_rrs = 0;
266 dr = NULL;
267 dane_tlsa = NULL;
268 len = strlen(name);
269 if (len > 1 && name[len - 1] == '.')
270 {
271 len--;
272 name[len] = '\0';
273 }
274 else
275 len = -1;
276 if (0 == port || tTd(66, 10))
277 port = 25;
278 (void) sm_snprintf(key, sizeof(key), "_%u..%s", port, name);
279 ste = stab(key, ST_TLSA_RR, ST_FIND);
280 if (tTd(8, 2))
281 sm_dprintf("gettlsa(%s, %s, ste=%p, pste=%p, flags=%lX, port=%d)\n",
282 host, isrname ? "" : name, (void *)ste, (void *)pste,
283 flags, port);
284
285 if (ste != NULL)
286 {
287 dane_tlsa = ste->s_tlsa;
288 if ((TLSAFLADMX & flags) != 0)
289 TLSA_CLR_FL(ste->s_tlsa, TLSAFLNOADMX);
290 }
291
292 /* Do not reload TLSA RRs if the MX RRs were not securely retrieved. */
293 if (pste != NULL
294 && dane_tlsa != NULL && TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX)
295 && DANE_SECURE == Dane)
296 goto end;
297
298 if (ste != NULL)
299 {
300 SM_ASSERT(dane_tlsa != NULL);
301 now = curtime();
302 if (dane_tlsa->dane_tlsa_exp <= now
303 && 0 == (TLSAFLNOEXP & flags))
304 dane_tlsa_clr(dane_tlsa);
305 else
306 {
307 n_rrs = dane_tlsa->dane_tlsa_n;
308 goto end;
309 }
310 }
311
312 if (dane_tlsa == NULL)
313 {
314 dane_tlsa = (dane_tlsa_P) sm_malloc(sizeof(*dane_tlsa));
315 if (dane_tlsa == NULL)
316 {
317 n_rrs = -ENOMEM;
318 goto end;
319 }
320 memset(dane_tlsa, '\0', sizeof(*dane_tlsa));
321 }
322
323 /* There are flags to store -- just set those, do nothing else. */
324 if (TLSA_STORE_FL(flags))
325 {
326 dane_tlsa->dane_tlsa_flags = flags;
327 ttl = mxttl > 0 ? mxttl: SM_DEFAULT_TTL;
328 goto done;
329 }
330
331 (void) sm_snprintf(nbuf, sizeof(nbuf), "_%u._tcp.%s", port, host);
332 dr = dns_lookup_int(nbuf, C_IN, T_TLSA, 0, 0,
333 TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX) ? 0 : SM_RES_DNSSEC,
334 RR_RAW, &err, &herr);
335 if (tTd(8, 2))
336 sm_dprintf("gettlsa(%s), dr=%p, ad=%d, err=%d, herr=%d\n", host,
337 (void *)dr, dr != NULL ? dr->dns_r_h.ad : -1, err, herr);
338 ttl = UINT_MAX;
339 n_rrs = tlsaadd(key, dr, dane_tlsa, herr, n_rrs, &ttl, 0);
340
341 /* no valid entries found? */
342 if (n_rrs == 0 && !TLSA_RR_TEMPFAIL(dane_tlsa))
343 {
344 if (tTd(8, 2))
345 sm_dprintf("gettlsa(%s), n_rrs=%d, herr=%d, status=NOT_ADDED\n",
346 host, n_rrs, dane_tlsa->dane_tlsa_dnsrc);
347 goto cleanup;
348 }
349
350 done:
351 dane_tlsa->dane_tlsa_n = n_rrs;
352 if (!isrname)
353 {
354 SM_FREE(dane_tlsa->dane_tlsa_sni);
355 dane_tlsa->dane_tlsa_sni = sm_strdup(host);
356 }
357 if (NULL == ste)
358 {
359 ste = stab(key, ST_TLSA_RR, ST_ENTER);
360 if (NULL == ste)
361 goto error;
362 }
363 ste->s_tlsa = dane_tlsa;
364 if (now == 0)
365 now = curtime();
366 dane_tlsa->dane_tlsa_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL);
367 dns_free_data(dr);
368 dr = NULL;
369 goto end;
370
371 error:
372 if (tTd(8, 2))
373 sm_dprintf("gettlsa(%s, %s), status=error\n", host, key);
374 n_rrs = -1;
375 cleanup:
376 if (NULL == ste)
377 dane_tlsa_free(dane_tlsa);
378 dns_free_data(dr);
379 dr = NULL;
380
381 end:
382 if (pste != NULL && ste != NULL)
383 *pste = ste;
384 if (len > 0)
385 host[len] = '.';
386 return n_rrs;
387 }
388 # endif /* DANE */
389
390 /*
391 ** GETFALLBACKMXRR -- get MX resource records for fallback MX host.
392 **
393 ** We have to initialize this once before doing anything else.
394 ** Moreover, we have to repeat this from time to time to avoid
395 ** stale data, e.g., in persistent queue runners.
396 ** This should be done in a parent process so the child
397 ** processes have the right data.
398 **
399 ** Parameters:
400 ** host -- the name of the fallback MX host.
401 **
402 ** Returns:
403 ** number of MX records.
404 **
405 ** Side Effects:
406 ** Populates NumFallbackMXHosts and fbhosts.
407 ** Sets renewal time (based on TTL).
408 */
409
410 int NumFallbackMXHosts = 0; /* Number of fallback MX hosts (after MX expansion) */
411 static char *fbhosts[MAXMXHOSTS + 1];
412
413 int
getfallbackmxrr(host)414 getfallbackmxrr(host)
415 char *host;
416 {
417 int i, rcode;
418 int ttl;
419 static time_t renew = 0;
420
421 #if 0
422 /* This is currently done before this function is called. */
423 if (host == NULL || *host == '\0')
424 return 0;
425 #endif /* 0 */
426 if (NumFallbackMXHosts > 0 && renew > curtime())
427 return NumFallbackMXHosts;
428
429 /* for DANE we need to invoke getmxrr() to get the TLSA RRs. */
430 #if !DANE
431 if (host[0] == '[')
432 {
433 fbhosts[0] = host;
434 NumFallbackMXHosts = 1;
435 }
436 else
437 #endif
438 {
439 /* free old data */
440 for (i = 0; i < NumFallbackMXHosts; i++)
441 sm_free(fbhosts[i]);
442
443 /*
444 ** Get new data.
445 ** Note: passing 0 as port is not correct but we cannot
446 ** determine the port number as there is no mailer.
447 */
448
449 NumFallbackMXHosts = getmxrr(host, fbhosts, NULL,
450 #if DANE
451 (DANE_SECURE == Dane) ? ISAD :
452 #endif
453 0,
454 &rcode, &ttl, 0);
455 renew = curtime() + ttl;
456 for (i = 0; i < NumFallbackMXHosts; i++)
457 fbhosts[i] = newstr(fbhosts[i]);
458 }
459 if (NumFallbackMXHosts == NULLMX)
460 NumFallbackMXHosts = 0;
461 return NumFallbackMXHosts;
462 }
463
464 /*
465 ** FALLBACKMXRR -- add MX resource records for fallback MX host to list.
466 **
467 ** Parameters:
468 ** nmx -- current number of MX records.
469 ** prefs -- array of preferences.
470 ** mxhosts -- array of MX hosts (maximum size: MAXMXHOSTS)
471 **
472 ** Returns:
473 ** new number of MX records.
474 **
475 ** Side Effects:
476 ** If FallbackMX was set, it appends the MX records for
477 ** that host to mxhosts (and modifies prefs accordingly).
478 */
479
480 static int
fallbackmxrr(nmx,prefs,mxhosts)481 fallbackmxrr(nmx, prefs, mxhosts)
482 int nmx;
483 unsigned short *prefs;
484 char **mxhosts;
485 {
486 int i;
487
488 for (i = 0; i < NumFallbackMXHosts && nmx < MAXMXHOSTS; i++)
489 {
490 if (nmx > 0)
491 prefs[nmx] = prefs[nmx - 1] + 1;
492 else
493 prefs[nmx] = 0;
494 mxhosts[nmx++] = fbhosts[i];
495 }
496 return nmx;
497 }
498
499 /*
500 ** GETMXRR -- get MX resource records for a domain
501 **
502 ** Parameters:
503 ** host -- the name of the host to MX.
504 ** mxhosts -- a pointer to a return buffer of MX records.
505 ** mxprefs -- a pointer to a return buffer of MX preferences.
506 ** If NULL, don't try to populate.
507 ** flags -- flags:
508 ** DROPLOCALHOSt -- If true, all MX records less preferred
509 ** than the local host (as determined by $=w) will
510 ** be discarded.
511 ** TRYFALLBACK -- add also fallback MX host?
512 ** ISAD -- host lookup was secure?
513 ** rcode -- a pointer to an EX_ status code.
514 ** pttl -- pointer to return TTL (can be NULL).
515 **
516 ** Returns:
517 ** The number of MX records found.
518 ** -1 if there is an internal failure.
519 ** If no MX records are found, mxhosts[0] is set to host
520 ** and 1 is returned.
521 **
522 ** Side Effects:
523 ** The entries made for mxhosts point to a static array
524 ** MXHostBuf[MXHOSTBUFSIZE], so the data needs to be copied,
525 ** if it must be preserved across calls to this function.
526 */
527
528 int
getmxrr(host,mxhosts,mxprefs,flags,rcode,pttl,port)529 getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
530 char *host;
531 char **mxhosts;
532 unsigned short *mxprefs;
533 unsigned int flags;
534 int *rcode;
535 int *pttl;
536 int port;
537 {
538 register unsigned char *eom, *cp;
539 register int i, j, n;
540 int nmx = 0;
541 register char *bp;
542 HEADER *hp;
543 querybuf answer;
544 int ancount, qdcount, buflen;
545 bool seenlocal = false;
546 unsigned short pref, type;
547 unsigned short localpref = 256;
548 char *fallbackMX = FallbackMX;
549 bool trycanon = false;
550 unsigned short *prefs;
551 int (*resfunc) __P((const char *, int, int, u_char *, int));
552 unsigned short prefer[MAXMXHOSTS];
553 int weight[MAXMXHOSTS];
554 int ttl = 0;
555 bool ad;
556 bool seennullmx = false;
557 extern int res_query(), res_search();
558 # if DANE
559 bool cname2mx;
560 char qname[MAXNAME];
561 unsigned long old_options = 0;
562 # endif
563
564 if (tTd(8, 2))
565 sm_dprintf("getmxrr(%s, droplocalhost=%d, flags=%X, port=%d)\n",
566 host, (flags & DROPLOCALHOST) != 0, flags, port);
567 ad = (flags & ISAD) != 0;
568 *rcode = EX_OK;
569 if (pttl != NULL)
570 *pttl = SM_DEFAULT_TTL;
571 if (*host == '\0')
572 return 0;
573 # if DANE
574 cname2mx = false;
575 qname[0] = '\0';
576 old_options = _res.options;
577 if (ad)
578 _res.options |= SM_RES_DNSSEC;
579 # endif
580
581 if ((fallbackMX != NULL && (flags & DROPLOCALHOST) != 0 &&
582 wordinclass(fallbackMX, 'w')) || (flags & TRYFALLBACK) == 0)
583 {
584 /* don't use fallback for this pass */
585 fallbackMX = NULL;
586 }
587
588 if (mxprefs != NULL)
589 prefs = mxprefs;
590 else
591 prefs = prefer;
592
593 /* efficiency hack -- numeric or non-MX lookups */
594 if (host[0] == '[')
595 goto punt;
596
597 # if DANE
598 /*
599 ** NOTE: This only works if nocanonify is used,
600 ** otherwise the name is already rewritten.
601 */
602
603 /* always or only when "needed"? */
604 if (DANE_ALWAYS == Dane || (ad && DANE_SECURE == Dane))
605 (void) sm_strlcpy(qname, host, sizeof(qname));
606 # endif /* DANE */
607
608 # if _FFR_EAI
609 if (!addr_is_ascii(host))
610 {
611 char buf[1024];
612 UErrorCode error = U_ZERO_ERROR;
613 UIDNAInfo info = UIDNA_INFO_INITIALIZER;
614 UIDNA *idna;
615
616 idna = uidna_openUTS46(UIDNA_NONTRANSITIONAL_TO_ASCII, &error);
617 (void) uidna_nameToASCII_UTF8(idna, host, strlen(host),
618 buf, sizeof(buf) - 1,
619 &info, &error);
620 uidna_close(idna);
621 host = sm_rpool_strdup_x(CurEnv->e_rpool, buf);
622 }
623 # endif /* _FFR_EAI */
624
625 /*
626 ** If we don't have MX records in our host switch, don't
627 ** try for MX records. Note that this really isn't "right",
628 ** since we might be set up to try NIS first and then DNS;
629 ** if the host is found in NIS we really shouldn't be doing
630 ** MX lookups. However, that should be a degenerate case.
631 */
632
633 if (!UseNameServer)
634 goto punt;
635 if (HasWildcardMX && ConfigLevel >= 6)
636 resfunc = res_query;
637 else
638 resfunc = res_search;
639 # if DNSSEC_TEST
640 if (tTd(8, 110))
641 resfunc = tstdns_search;
642 # endif
643
644 errno = 0;
645 hp = (HEADER *)&answer;
646 n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer,
647 sizeof(answer));
648 if (n < 0)
649 {
650 if (tTd(8, 1))
651 # if DNSSEC_TEST
652 sm_dprintf("getmxrr: res_search(%s) failed (errno=%d (%s), h_errno=%d (%s))\n",
653 host, errno, strerror(errno),
654 h_errno, herrno2txt(h_errno));
655 # else
656 sm_dprintf("getmxrr: res_search(%s) failed, h_errno=%d\n",
657 host, h_errno);
658 # endif
659 switch (h_errno)
660 {
661 case NO_DATA:
662 trycanon = true;
663 /* FALLTHROUGH */
664
665 case NO_RECOVERY:
666 /* no MX data on this host */
667 goto punt;
668
669 case HOST_NOT_FOUND:
670 # if BROKEN_RES_SEARCH
671 case 0: /* Ultrix resolver returns failure w/ h_errno=0 */
672 # endif
673 /* host doesn't exist in DNS; might be in /etc/hosts */
674 trycanon = true;
675 *rcode = EX_NOHOST;
676 goto punt;
677
678 case TRY_AGAIN:
679 case -1:
680 /* couldn't connect to the name server */
681 if (fallbackMX != NULL)
682 {
683 /* name server is hosed -- push to fallback */
684 nmx = fallbackmxrr(nmx, prefs, mxhosts);
685 goto done;
686 }
687 /* it might come up later; better queue it up */
688 *rcode = EX_TEMPFAIL;
689 break;
690
691 default:
692 syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)",
693 host, h_errno);
694 *rcode = EX_OSERR;
695 break;
696 }
697
698 /* irreconcilable differences */
699 goto error;
700 }
701
702 ad = ad && hp->ad;
703 if (tTd(8, 2))
704 sm_dprintf("getmxrr(%s), hp=%p, ad=%d\n", host, (void*)hp, ad);
705
706 /* avoid problems after truncation in tcp packets */
707 if (n > sizeof(answer))
708 n = sizeof(answer);
709
710 /* find first satisfactory answer */
711 cp = (unsigned char *)&answer + HFIXEDSZ;
712 eom = (unsigned char *)&answer + n;
713
714 for (qdcount = ntohs((unsigned short) hp->qdcount);
715 qdcount--;
716 cp += n + QFIXEDSZ)
717 {
718 if ((n = dn_skipname(cp, eom)) < 0)
719 goto punt;
720 }
721
722 /* NOTE: see definition of MXHostBuf! */
723 buflen = sizeof(MXHostBuf) - 1;
724 SM_ASSERT(buflen > 0);
725 bp = MXHostBuf;
726 ancount = ntohs((unsigned short) hp->ancount);
727
728 /* See RFC 1035 for layout of RRs. */
729 /* XXX leave room for FallbackMX ? */
730 while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
731 {
732 if ((n = dn_expand((unsigned char *)&answer, eom, cp,
733 (RES_UNC_T) bp, buflen)) < 0)
734 break;
735 cp += n;
736 GETSHORT(type, cp);
737 cp += INT16SZ; /* skip over class */
738 GETLONG(ttl, cp);
739 GETSHORT(n, cp); /* rdlength */
740 # if DANE
741 if (type == T_CNAME)
742 cname2mx = true;
743 # endif
744 if (type != T_MX)
745 {
746 if ((tTd(8, 8) || _res.options & RES_DEBUG)
747 # if DANE
748 && type != T_RRSIG
749 # endif
750 )
751 sm_dprintf("unexpected answer type %s, size %d\n",
752 dns_type_to_string(type), n);
753 cp += n;
754 continue;
755 }
756 GETSHORT(pref, cp);
757 if ((n = dn_expand((unsigned char *)&answer, eom, cp,
758 (RES_UNC_T) bp, buflen)) < 0)
759 break;
760 cp += n;
761 n = strlen(bp);
762
763 /* Support for RFC7505 "MX 0 ." */
764 if (pref == 0 && *bp == '\0')
765 seennullmx = true;
766
767 if (wordinclass(bp, 'w'))
768 {
769 if (tTd(8, 3))
770 sm_dprintf("found localhost (%s) in MX list, pref=%d\n",
771 bp, pref);
772 if ((flags & DROPLOCALHOST) != 0)
773 {
774 if (!seenlocal || pref < localpref)
775 localpref = pref;
776 seenlocal = true;
777 continue;
778 }
779 weight[nmx] = 0;
780 }
781 else
782 weight[nmx] = mxrand(bp);
783 prefs[nmx] = pref;
784 mxhosts[nmx++] = bp;
785 # if DANE
786 if (CHK_DANE(Dane) && port >= 0)
787 {
788 int nrr;
789 unsigned long flags;
790
791 flags = ad ? TLSAFLADMX : TLSAFLNOADMX;
792 nrr = gettlsa(bp, NULL, NULL, flags, ttl, port);
793
794 /* Only check qname if no TLSA RRs were found */
795 if (0 == nrr && cname2mx && '\0' != qname[0] &&
796 strcmp(qname, bp))
797 gettlsa(qname, bp, NULL, flags, ttl, port);
798 /* XXX is this the right ad flag? */
799 }
800 # endif
801
802 /*
803 ** Note: n can be 0 for something like:
804 ** host MX 0 .
805 ** See RFC 7505
806 */
807
808 bp += n;
809 if (0 == n || bp[-1] != '.')
810 {
811 *bp++ = '.';
812 n++;
813 }
814 *bp++ = '\0';
815 if (buflen < n + 1)
816 {
817 /* don't want to wrap buflen */
818 break;
819 }
820 buflen -= n + 1;
821 }
822
823 /* Support for RFC7505 "MX 0 ." */
824 if (seennullmx && nmx == 1)
825 {
826 if (tTd(8, 4))
827 sm_dprintf("getmxrr: Null MX record found, domain doesn't accept mail (RFC7505)\n");
828 *rcode = EX_UNAVAILABLE;
829 return NULLMX;
830 }
831
832 /* return only one TTL entry, that should be sufficient */
833 if (ttl > 0 && pttl != NULL)
834 *pttl = ttl;
835
836 /* sort the records */
837 for (i = 0; i < nmx; i++)
838 {
839 for (j = i + 1; j < nmx; j++)
840 {
841 if (prefs[i] > prefs[j] ||
842 (prefs[i] == prefs[j] && weight[i] > weight[j]))
843 {
844 register int temp;
845 register char *temp1;
846
847 temp = prefs[i];
848 prefs[i] = prefs[j];
849 prefs[j] = temp;
850 temp1 = mxhosts[i];
851 mxhosts[i] = mxhosts[j];
852 mxhosts[j] = temp1;
853 temp = weight[i];
854 weight[i] = weight[j];
855 weight[j] = temp;
856 }
857 }
858 if (seenlocal && prefs[i] >= localpref)
859 {
860 /* truncate higher preference part of list */
861 nmx = i;
862 }
863 }
864
865 /* delete duplicates from list (yes, some bozos have duplicates) */
866 for (i = 0; i < nmx - 1; )
867 {
868 if (sm_strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0)
869 i++;
870 else
871 {
872 /* compress out duplicate */
873 for (j = i + 1; j < nmx; j++)
874 {
875 mxhosts[j] = mxhosts[j + 1];
876 prefs[j] = prefs[j + 1];
877 }
878 nmx--;
879 }
880 }
881
882 if (nmx == 0)
883 {
884 punt:
885 if (seenlocal)
886 {
887 struct hostent *h = NULL;
888
889 /*
890 ** If we have deleted all MX entries, this is
891 ** an error -- we should NEVER send to a host that
892 ** has an MX, and this should have been caught
893 ** earlier in the config file.
894 **
895 ** Some sites prefer to go ahead and try the
896 ** A record anyway; that case is handled by
897 ** setting TryNullMXList. I believe this is a
898 ** bad idea, but it's up to you....
899 */
900
901 if (TryNullMXList)
902 {
903 SM_SET_H_ERRNO(0);
904 errno = 0;
905 h = sm_gethostbyname(host, AF_INET);
906 if (h == NULL)
907 {
908 if (errno == ETIMEDOUT ||
909 h_errno == TRY_AGAIN ||
910 (errno == ECONNREFUSED &&
911 UseNameServer))
912 {
913 *rcode = EX_TEMPFAIL;
914 goto error;
915 }
916 # if NETINET6
917 SM_SET_H_ERRNO(0);
918 errno = 0;
919 h = sm_gethostbyname(host, AF_INET6);
920 if (h == NULL &&
921 (errno == ETIMEDOUT ||
922 h_errno == TRY_AGAIN ||
923 (errno == ECONNREFUSED &&
924 UseNameServer)))
925 {
926 *rcode = EX_TEMPFAIL;
927 goto error;
928 }
929 # endif /* NETINET6 */
930 }
931 }
932
933 if (h == NULL)
934 {
935 *rcode = EX_CONFIG;
936 syserr("MX list for %s points back to %s",
937 host, MyHostName);
938 goto error;
939 }
940 # if NETINET6
941 freehostent(h);
942 h = NULL;
943 # endif
944 }
945 if (strlen(host) >= sizeof(MXHostBuf))
946 {
947 *rcode = EX_CONFIG;
948 syserr("Host name %s too long",
949 shortenstring(host, MAXSHORTSTR));
950 goto error;
951 }
952 (void) sm_strlcpy(MXHostBuf, host, sizeof(MXHostBuf));
953 mxhosts[0] = MXHostBuf;
954 prefs[0] = 0;
955 if (host[0] == '[')
956 {
957 register char *p;
958 # if NETINET6
959 struct sockaddr_in6 tmp6;
960 # endif
961
962 /* this may be an MX suppression-style address */
963 p = strchr(MXHostBuf, ']');
964 if (p != NULL)
965 {
966 *p = '\0';
967
968 if (inet_addr(&MXHostBuf[1]) != INADDR_NONE)
969 {
970 nmx++;
971 *p = ']';
972 }
973 # if NETINET6
974 else if (anynet_pton(AF_INET6, &MXHostBuf[1],
975 &tmp6.sin6_addr) == 1)
976 {
977 nmx++;
978 *p = ']';
979 }
980 # endif /* NETINET6 */
981 else
982 {
983 trycanon = true;
984 mxhosts[0]++;
985 }
986 }
987 }
988 if (trycanon &&
989 (n = getcanonname(mxhosts[0], sizeof(MXHostBuf) - 2, false,
990 pttl)) != HOST_NOTFOUND)
991 {
992 /* XXX MXHostBuf == "" ? is that possible? */
993 bp = &MXHostBuf[strlen(MXHostBuf)];
994 if (bp[-1] != '.')
995 {
996 *bp++ = '.';
997 *bp = '\0';
998 }
999 nmx = 1;
1000 # if DANE
1001 if (tTd(8, 3))
1002 sm_dprintf("getmxrr=%s, getcanonname=%d\n",
1003 mxhosts[0], n);
1004 if (CHK_DANE(Dane) && port >= 0)
1005 {
1006 int nrr;
1007 unsigned long flags;
1008 unsigned int cttl;
1009
1010 if (pttl != NULL)
1011 cttl = *pttl;
1012 else if (ttl > 0)
1013 cttl = ttl;
1014 else
1015 cttl = SM_DEFAULT_TTL;
1016
1017 flags = (ad && n == HOST_SECURE)
1018 ? TLSAFLADMX : TLSAFLNOADMX;
1019 nrr = gettlsa(mxhosts[0], NULL, NULL, flags,
1020 cttl, port);
1021
1022 /*
1023 ** Only check qname if no TLSA RRs were found
1024 ** XXX: what about (temp) DNS errors?
1025 */
1026
1027 if (0 == nrr && '\0' != qname[0] &&
1028 strcmp(qname, mxhosts[0]))
1029 gettlsa(qname, mxhosts[0], NULL, flags,
1030 cttl, port);
1031 /* XXX is this the right ad flag? */
1032 }
1033 # endif
1034 }
1035 }
1036
1037 /* if we have a default lowest preference, include that */
1038 if (fallbackMX != NULL && !seenlocal)
1039 {
1040 /* TODO: DNSsec status of fallbacks */
1041 nmx = fallbackmxrr(nmx, prefs, mxhosts);
1042 }
1043 done:
1044 # if DANE
1045 _res.options = old_options;
1046 # endif
1047 return nmx;
1048
1049 error:
1050 # if DANE
1051 _res.options = old_options;
1052 # endif
1053 return -1;
1054 }
1055
1056 /*
1057 ** MXRAND -- create a randomizer for equal MX preferences
1058 **
1059 ** If two MX hosts have equal preferences we want to randomize
1060 ** the selection. But in order for signatures to be the same,
1061 ** we need to randomize the same way each time. This function
1062 ** computes a pseudo-random hash function from the host name.
1063 **
1064 ** Parameters:
1065 ** host -- the name of the host.
1066 **
1067 ** Returns:
1068 ** A random but repeatable value based on the host name.
1069 */
1070
1071 static int
mxrand(host)1072 mxrand(host)
1073 register char *host;
1074 {
1075 int hfunc;
1076 static unsigned int seed;
1077
1078 if (seed == 0)
1079 {
1080 seed = (int) curtime() & 0xffff;
1081 if (seed == 0)
1082 seed++;
1083 }
1084
1085 if (tTd(17, 9))
1086 sm_dprintf("mxrand(%s)", host);
1087
1088 hfunc = seed;
1089 while (*host != '\0')
1090 {
1091 int c = *host++;
1092
1093 if (isascii(c) && isupper(c))
1094 c = tolower(c);
1095 hfunc = ((hfunc << 1) ^ c) % 2003;
1096 }
1097
1098 hfunc &= 0xff;
1099 hfunc++;
1100
1101 if (tTd(17, 9))
1102 sm_dprintf(" = %d\n", hfunc);
1103 return hfunc;
1104 }
1105 /*
1106 ** BESTMX -- find the best MX for a name
1107 **
1108 ** This is really a hack, but I don't see any obvious way
1109 ** to generalize it at the moment.
1110 */
1111
1112 /* ARGSUSED3 */
1113 char *
bestmx_map_lookup(map,name,av,statp)1114 bestmx_map_lookup(map, name, av, statp)
1115 MAP *map;
1116 char *name;
1117 char **av;
1118 int *statp;
1119 {
1120 int nmx;
1121 int saveopts = _res.options;
1122 int i;
1123 ssize_t len = 0;
1124 char *result;
1125 char *mxhosts[MAXMXHOSTS + 1];
1126 # if _FFR_BESTMX_BETTER_TRUNCATION
1127 char *buf;
1128 # else
1129 char *p;
1130 char buf[PSBUFSIZE / 2];
1131 # endif
1132
1133 _res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
1134 nmx = getmxrr(name, mxhosts, NULL, 0, statp, NULL, -1);
1135 _res.options = saveopts;
1136 if (nmx <= 0)
1137 return NULL;
1138 if (bitset(MF_MATCHONLY, map->map_mflags))
1139 return map_rewrite(map, name, strlen(name), NULL);
1140 if ((map->map_coldelim == '\0') || (nmx == 1))
1141 return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
1142
1143 /*
1144 ** We were given a -z flag (return all MXs) and there are multiple
1145 ** ones. We need to build them all into a list.
1146 */
1147
1148 # if _FFR_BESTMX_BETTER_TRUNCATION
1149 for (i = 0; i < nmx; i++)
1150 {
1151 if (strchr(mxhosts[i], map->map_coldelim) != NULL)
1152 {
1153 syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
1154 mxhosts[i], map->map_coldelim);
1155 return NULL;
1156 }
1157 len += strlen(mxhosts[i]) + 1;
1158 if (len < 0)
1159 {
1160 len -= strlen(mxhosts[i]) + 1;
1161 break;
1162 }
1163 }
1164 buf = (char *) sm_malloc(len);
1165 if (buf == NULL)
1166 {
1167 *statp = EX_UNAVAILABLE;
1168 return NULL;
1169 }
1170 *buf = '\0';
1171 for (i = 0; i < nmx; i++)
1172 {
1173 int end;
1174
1175 end = sm_strlcat(buf, mxhosts[i], len);
1176 if (i != nmx && end + 1 < len)
1177 {
1178 buf[end] = map->map_coldelim;
1179 buf[end + 1] = '\0';
1180 }
1181 }
1182
1183 /* Cleanly truncate for rulesets */
1184 truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim);
1185 # else /* _FFR_BESTMX_BETTER_TRUNCATION */
1186 p = buf;
1187 for (i = 0; i < nmx; i++)
1188 {
1189 size_t slen;
1190
1191 if (strchr(mxhosts[i], map->map_coldelim) != NULL)
1192 {
1193 syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
1194 mxhosts[i], map->map_coldelim);
1195 return NULL;
1196 }
1197 slen = strlen(mxhosts[i]);
1198 if (len + slen + 2 > sizeof(buf))
1199 break;
1200 if (i > 0)
1201 {
1202 *p++ = map->map_coldelim;
1203 len++;
1204 }
1205 (void) sm_strlcpy(p, mxhosts[i], sizeof(buf) - len);
1206 p += slen;
1207 len += slen;
1208 }
1209 # endif /* _FFR_BESTMX_BETTER_TRUNCATION */
1210
1211 result = map_rewrite(map, buf, len, av);
1212 # if _FFR_BESTMX_BETTER_TRUNCATION
1213 sm_free(buf);
1214 # endif
1215 return result;
1216 }
1217 /*
1218 ** DNS_GETCANONNAME -- get the canonical name for named host using DNS
1219 **
1220 ** This algorithm tries to be smart about wildcard MX records.
1221 ** This is hard to do because DNS doesn't tell is if we matched
1222 ** against a wildcard or a specific MX.
1223 **
1224 ** We always prefer A & CNAME records, since these are presumed
1225 ** to be specific.
1226 **
1227 ** If we match an MX in one pass and lose it in the next, we use
1228 ** the old one. For example, consider an MX matching *.FOO.BAR.COM.
1229 ** A hostname bletch.foo.bar.com will match against this MX, but
1230 ** will stop matching when we try bletch.bar.com -- so we know
1231 ** that bletch.foo.bar.com must have been right. This fails if
1232 ** there was also an MX record matching *.BAR.COM, but there are
1233 ** some things that just can't be fixed.
1234 **
1235 ** Parameters:
1236 ** host -- a buffer containing the name of the host.
1237 ** This is a value-result parameter.
1238 ** hbsize -- the size of the host buffer.
1239 ** trymx -- if set, try MX records as well as A and CNAME.
1240 ** statp -- pointer to place to store status.
1241 ** pttl -- pointer to return TTL (can be NULL).
1242 **
1243 ** Returns:
1244 ** >0 -- if the host was found.
1245 ** 0 -- otherwise.
1246 */
1247
1248 int
dns_getcanonname(host,hbsize,trymx,statp,pttl)1249 dns_getcanonname(host, hbsize, trymx, statp, pttl)
1250 char *host;
1251 int hbsize;
1252 bool trymx;
1253 int *statp;
1254 int *pttl;
1255 {
1256 register unsigned char *eom, *ap;
1257 register char *cp;
1258 register int n;
1259 HEADER *hp;
1260 querybuf answer;
1261 int ancount, qdcount, ret, type, qtype, initial, loopcnt, ttl, sli;
1262 char **domain;
1263 char *dp;
1264 char *mxmatch;
1265 bool amatch, gotmx, ad;
1266 char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)];
1267 # if DNSSEC_TEST
1268 # define ADDSL 1 /* NameSearchList may add another entry to searchlist! */
1269 # else
1270 # define ADDSL 0
1271 # endif
1272 char *searchlist[MAXDNSRCH + 2 + ADDSL];
1273 # define SLSIZE SM_ARRAY_SIZE(searchlist)
1274 int (*resqdomain) __P((const char *, const char *, int, int, unsigned char *, int));
1275 # if DANE
1276 unsigned long old_options = 0;
1277 # endif
1278
1279 ttl = 0;
1280 gotmx = false;
1281 ad = true;
1282 if (tTd(8, 2))
1283 sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
1284
1285 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
1286 {
1287 *statp = EX_UNAVAILABLE;
1288 return HOST_NOTFOUND;
1289 }
1290
1291 # if DANE
1292 old_options = _res.options;
1293 if (DANE_SECURE == Dane)
1294 _res.options |= SM_RES_DNSSEC;
1295 # endif
1296
1297 *statp = EX_OK;
1298 resqdomain = res_querydomain;
1299 # if DNSSEC_TEST
1300 if (tTd(8, 110))
1301 resqdomain = tstdns_querydomain;
1302 # endif
1303
1304 /*
1305 ** Initialize domain search list. If there is at least one
1306 ** dot in the name, search the unmodified name first so we
1307 ** find "vse.CS" in Czechoslovakia instead of in the local
1308 ** domain (e.g., vse.CS.Berkeley.EDU). Note that there is no
1309 ** longer a country named Czechoslovakia but this type of problem
1310 ** is still present.
1311 **
1312 ** Older versions of the resolver could create this
1313 ** list by tearing apart the host name.
1314 */
1315
1316 loopcnt = 0;
1317 cnameloop:
1318 /* Check for dots in the name */
1319 for (cp = host, n = 0; *cp != '\0'; cp++)
1320 if (*cp == '.')
1321 n++;
1322
1323 /*
1324 ** Build the search list.
1325 ** If there is at least one dot in name, start with a null
1326 ** domain to search the unmodified name first.
1327 ** If name does not end with a dot and search up local domain
1328 ** tree desired, append each local domain component to the
1329 ** search list; if name contains no dots and default domain
1330 ** name is desired, append default domain name to search list;
1331 ** else if name ends in a dot, remove that dot.
1332 */
1333
1334 sli = 0;
1335 if (n > 0)
1336 searchlist[sli++] = "";
1337 # if DNSSEC_TEST
1338 if (NameSearchList != NULL)
1339 {
1340 SM_ASSERT(sli < SLSIZE);
1341 searchlist[sli++] = NameSearchList;
1342 }
1343 # endif
1344 if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options))
1345 {
1346 /* make sure there are less than MAXDNSRCH domains */
1347 for (domain = RES_DNSRCH_VARIABLE, ret = 0;
1348 *domain != NULL && ret < MAXDNSRCH && sli < SLSIZE;
1349 ret++)
1350 searchlist[sli++] = *domain++;
1351 }
1352 else if (n == 0 && bitset(RES_DEFNAMES, _res.options))
1353 {
1354 SM_ASSERT(sli < SLSIZE);
1355 searchlist[sli++] = _res.defdname;
1356 }
1357 else if (*cp == '.')
1358 {
1359 *cp = '\0';
1360 }
1361 SM_ASSERT(sli < SLSIZE);
1362 searchlist[sli] = NULL;
1363
1364 /*
1365 ** Now loop through the search list, appending each domain in turn
1366 ** name and searching for a match.
1367 */
1368
1369 mxmatch = NULL;
1370 initial = T_A;
1371 # if NETINET6
1372 if (InetMode == AF_INET6)
1373 initial = T_AAAA;
1374 # endif
1375 qtype = initial;
1376
1377 for (sli = 0; sli < SLSIZE; )
1378 {
1379 dp = searchlist[sli];
1380 if (NULL == dp)
1381 break;
1382 if (qtype == initial)
1383 gotmx = false;
1384 if (tTd(8, 5))
1385 sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n",
1386 host, dp,
1387 # if NETINET6
1388 qtype == T_AAAA ? "AAAA" :
1389 # endif
1390 qtype == T_A ? "A" :
1391 qtype == T_MX ? "MX" :
1392 "???");
1393 errno = 0;
1394 hp = (HEADER *) &answer;
1395 ret = (*resqdomain)(host, dp, C_IN, qtype,
1396 answer.qb2, sizeof(answer.qb2));
1397 if (ret <= 0)
1398 {
1399 int save_errno = errno;
1400
1401 if (tTd(8, 7))
1402 sm_dprintf("\tNO: errno=%d, h_errno=%d\n",
1403 save_errno, h_errno);
1404
1405 if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN)
1406 {
1407 /*
1408 ** the name server seems to be down or broken.
1409 */
1410
1411 SM_SET_H_ERRNO(TRY_AGAIN);
1412 if (*dp == '\0')
1413 {
1414 if (*statp == EX_OK)
1415 *statp = EX_TEMPFAIL;
1416 goto nexttype;
1417 }
1418 *statp = EX_TEMPFAIL;
1419
1420 if (WorkAroundBrokenAAAA)
1421 {
1422 /*
1423 ** Only return if not TRY_AGAIN as an
1424 ** attempt with a different qtype may
1425 ** succeed (res_querydomain() calls
1426 ** res_query() calls res_send() which
1427 ** sets errno to ETIMEDOUT if the
1428 ** nameservers could be contacted but
1429 ** didn't give an answer).
1430 */
1431
1432 if (save_errno != ETIMEDOUT)
1433 goto error;
1434 }
1435 else
1436 goto error;
1437 }
1438
1439 nexttype:
1440 if (h_errno != HOST_NOT_FOUND)
1441 {
1442 /* might have another type of interest */
1443 # if NETINET6
1444 if (qtype == T_AAAA)
1445 {
1446 qtype = T_A;
1447 continue;
1448 }
1449 else
1450 # endif /* NETINET6 */
1451 if (qtype == T_A && !gotmx &&
1452 (trymx || *dp == '\0'))
1453 {
1454 qtype = T_MX;
1455 continue;
1456 }
1457 }
1458
1459 /* definite no -- try the next domain */
1460 sli++;
1461 qtype = initial;
1462 continue;
1463 }
1464 else if (tTd(8, 7))
1465 sm_dprintf("\tYES\n");
1466
1467 /* avoid problems after truncation in tcp packets */
1468 if (ret > sizeof(answer))
1469 ret = sizeof(answer);
1470 SM_ASSERT(ret >= 0);
1471
1472 /*
1473 ** Appear to have a match. Confirm it by searching for A or
1474 ** CNAME records. If we don't have a local domain
1475 ** wild card MX record, we will accept MX as well.
1476 */
1477
1478 ap = (unsigned char *) &answer + HFIXEDSZ;
1479 eom = (unsigned char *) &answer + ret;
1480
1481 if (0 == hp->ad)
1482 ad = false;
1483
1484 /* skip question part of response -- we know what we asked */
1485 for (qdcount = ntohs((unsigned short) hp->qdcount);
1486 qdcount--;
1487 ap += ret + QFIXEDSZ)
1488 {
1489 if ((ret = dn_skipname(ap, eom)) < 0)
1490 {
1491 if (tTd(8, 20))
1492 sm_dprintf("qdcount failure (%d)\n",
1493 ntohs((unsigned short) hp->qdcount));
1494 *statp = EX_SOFTWARE;
1495 goto error;
1496 }
1497 }
1498
1499 amatch = false;
1500 for (ancount = ntohs((unsigned short) hp->ancount);
1501 --ancount >= 0 && ap < eom;
1502 ap += n)
1503 {
1504 n = dn_expand((unsigned char *) &answer, eom, ap,
1505 (RES_UNC_T) nbuf, sizeof(nbuf));
1506 if (n < 0)
1507 break;
1508 ap += n;
1509 GETSHORT(type, ap);
1510 ap += INT16SZ; /* skip over class */
1511 GETLONG(ttl, ap);
1512 GETSHORT(n, ap); /* rdlength */
1513 switch (type)
1514 {
1515 case T_MX:
1516 gotmx = true;
1517 if (*dp != '\0' && HasWildcardMX)
1518 {
1519 /*
1520 ** If we are using MX matches and have
1521 ** not yet gotten one, save this one
1522 ** but keep searching for an A or
1523 ** CNAME match.
1524 */
1525
1526 if (trymx && mxmatch == NULL)
1527 mxmatch = dp;
1528 continue;
1529 }
1530
1531 /*
1532 ** If we did not append a domain name, this
1533 ** must have been a canonical name to start
1534 ** with. Even if we did append a domain name,
1535 ** in the absence of a wildcard MX this must
1536 ** still be a real MX match.
1537 ** Such MX matches are as good as an A match,
1538 ** fall through.
1539 */
1540 /* FALLTHROUGH */
1541
1542 # if NETINET6
1543 case T_AAAA:
1544 # endif
1545 case T_A:
1546 /* Flag that a good match was found */
1547 amatch = true;
1548
1549 /* continue in case a CNAME also exists */
1550 continue;
1551
1552 case T_CNAME:
1553 if (DontExpandCnames)
1554 {
1555 /* got CNAME -- guaranteed canonical */
1556 amatch = true;
1557 break;
1558 }
1559
1560 if (loopcnt++ > MAXCNAMEDEPTH)
1561 {
1562 /*XXX should notify postmaster XXX*/
1563 message("DNS failure: CNAME loop for %s",
1564 host);
1565 if (CurEnv->e_message == NULL)
1566 {
1567 char ebuf[MAXLINE];
1568
1569 (void) sm_snprintf(ebuf,
1570 sizeof(ebuf),
1571 "Deferred: DNS failure: CNAME loop for %.100s",
1572 host);
1573 CurEnv->e_message =
1574 sm_rpool_strdup_x(
1575 CurEnv->e_rpool, ebuf);
1576 }
1577 SM_SET_H_ERRNO(NO_RECOVERY);
1578 *statp = EX_CONFIG;
1579 goto error;
1580 }
1581
1582 /* value points at name */
1583 if ((ret = dn_expand((unsigned char *)&answer,
1584 eom, ap, (RES_UNC_T) nbuf,
1585 sizeof(nbuf))) < 0)
1586 break;
1587 (void) sm_strlcpy(host, nbuf, hbsize);
1588
1589 /*
1590 ** RFC 1034 section 3.6 specifies that CNAME
1591 ** should point at the canonical name -- but
1592 ** urges software to try again anyway.
1593 */
1594
1595 goto cnameloop;
1596
1597 default:
1598 /* not a record of interest */
1599 continue;
1600 }
1601 }
1602
1603 if (amatch)
1604 {
1605 /*
1606 ** Got a good match -- either an A, CNAME, or an
1607 ** exact MX record. Save it and get out of here.
1608 */
1609
1610 mxmatch = dp;
1611 break;
1612 }
1613
1614 /*
1615 ** Nothing definitive yet.
1616 ** If this was a T_A query and we haven't yet found a MX
1617 ** match, try T_MX if allowed to do so.
1618 ** Otherwise, try the next domain.
1619 */
1620
1621 # if NETINET6
1622 if (qtype == T_AAAA)
1623 qtype = T_A;
1624 else
1625 # endif
1626 if (qtype == T_A && !gotmx && (trymx || *dp == '\0'))
1627 qtype = T_MX;
1628 else
1629 {
1630 qtype = initial;
1631 sli++;
1632 }
1633 }
1634
1635 /* if nothing was found, we are done */
1636 if (mxmatch == NULL)
1637 {
1638 if (*statp == EX_OK)
1639 *statp = EX_NOHOST;
1640 goto error;
1641 }
1642
1643 /*
1644 ** Create canonical name and return.
1645 ** If saved domain name is null, name was already canonical.
1646 ** Otherwise append the saved domain name.
1647 */
1648
1649 (void) sm_snprintf(nbuf, sizeof(nbuf), "%.*s%s%.*s", MAXDNAME, host,
1650 *mxmatch == '\0' ? "" : ".",
1651 MAXDNAME, mxmatch);
1652 (void) sm_strlcpy(host, nbuf, hbsize);
1653 if (tTd(8, 5))
1654 sm_dprintf("dns_getcanonname: %s\n", host);
1655 *statp = EX_OK;
1656
1657 /* return only one TTL entry, that should be sufficient */
1658 if (ttl > 0 && pttl != NULL)
1659 *pttl = ttl;
1660 # if DANE
1661 _res.options = old_options;
1662 # endif
1663 return ad ? HOST_SECURE : HOST_OK;
1664
1665 error:
1666 # if DANE
1667 _res.options = old_options;
1668 # endif
1669 return HOST_NOTFOUND;
1670 }
1671
1672 #endif /* NAMED_BIND */
1673