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 USE_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 #include <sm/sendmail.h>
27
28 #if NAMED_BIND
29 # include <arpa/inet.h>
30 # include <sm_resolve.h>
31 # if DANE
32 # include <tls.h>
33 # ifndef SM_NEG_TTL
34 # define SM_NEG_TTL 60 /* "negative" TTL */
35 # endif
36 # endif
37
38
39 # ifndef MXHOSTBUFSIZE
40 # define MXHOSTBUFSIZE (128 * MAXMXHOSTS)
41 # endif
42
43 static char MXHostBuf[MXHOSTBUFSIZE];
44 # if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2)
45 ERROR: _MXHOSTBUFSIZE is out of range
46 # endif
47
48 # ifndef MAXDNSRCH
49 # define MAXDNSRCH 6 /* number of possible domains to search */
50 # endif
51
52 # ifndef RES_DNSRCH_VARIABLE
53 # define RES_DNSRCH_VARIABLE _res.dnsrch
54 # endif
55
56 # ifndef NO_DATA
57 # define NO_DATA NO_ADDRESS
58 # endif
59
60 # ifndef HFIXEDSZ
61 # define HFIXEDSZ 12 /* sizeof(HEADER) */
62 # endif
63
64 # define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */
65
66 # if defined(__RES) && (__RES >= 19940415)
67 # define RES_UNC_T char *
68 # else
69 # define RES_UNC_T unsigned char *
70 # endif
71
72 static int mxrand __P((char *));
73 static int fallbackmxrr __P((int, unsigned short *, char **));
74
75 # if DANE
76
77 /*
78 ** TLSAADD -- add TLSA records to dane_tlsa entry
79 **
80 ** Parameters:
81 ** name -- key for stab entry (for debugging output)
82 ** dr -- DNS reply
83 ** dane_tlsa -- dane_tlsa entry
84 ** dnsrc -- DNS lookup return code (h_errno)
85 ** n -- current number of TLSA records in dane_tlsa entry
86 ** pttl -- (pointer to) TTL (in/out)
87 ** level -- recursion level (CNAMEs)
88 **
89 ** Returns:
90 ** new number of TLSA records
91 */
92
93 static int tlsaadd __P((const char *, DNS_REPLY_T *, dane_tlsa_P, int, int,
94 unsigned int *, int));
95
96 static int
tlsaadd(name,dr,dane_tlsa,dnsrc,n,pttl,level)97 tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
98 const char *name;
99 DNS_REPLY_T *dr;
100 dane_tlsa_P dane_tlsa;
101 int dnsrc;
102 int n;
103 unsigned int *pttl;
104 int level;
105 {
106 RESOURCE_RECORD_T *rr;
107 unsigned int ttl;
108 int nprev;
109
110 if (dnsrc != 0)
111 {
112 if (tTd(8, 2))
113 sm_dprintf("tlsaadd(%s), prev=%d, dnsrc=%d\n",
114 name, dane_tlsa->dane_tlsa_dnsrc, dnsrc);
115
116 /* check previous error and keep the "most important" one? */
117 dane_tlsa->dane_tlsa_dnsrc = dnsrc;
118 # if DNSSEC_TEST
119 if (tTd(8, 110))
120 *pttl = tTdlevel(8)-110; /* how to make this an option? */
121 else
122 # endif
123 /* "else" in #if code above */
124 *pttl = SM_NEG_TTL;
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 (SM_IS_EMPTY(host))
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 # if USE_EAI
500
501 /*
502 ** HN2ALABEL -- convert hostname in U-label format to A-label format
503 **
504 ** Parameters:
505 ** hostname -- hostname in U-label format
506 **
507 ** Returns:
508 ** hostname in A-label format in a local static buffer.
509 ** It must be copied before the function is called again.
510 */
511
512 const char *
hn2alabel(hostname)513 hn2alabel(hostname)
514 const char *hostname;
515 {
516 UErrorCode error = U_ZERO_ERROR;
517 UIDNAInfo info = UIDNA_INFO_INITIALIZER;
518 UIDNA *idna;
519 static char buf[MAXNAME_I]; /* XXX ??? */
520
521 if (addr_is_ascii(hostname))
522 return hostname;
523 idna = uidna_openUTS46(UIDNA_NONTRANSITIONAL_TO_ASCII, &error);
524 (void) uidna_nameToASCII_UTF8(idna, hostname, strlen(hostname),
525 buf, sizeof(buf) - 1,
526 &info, &error);
527 uidna_close(idna);
528 return buf;
529 }
530 # endif /* USE_EAI */
531
532 /*
533 ** GETMXRR -- get MX resource records for a domain
534 **
535 ** Parameters:
536 ** host -- the name of the host to MX [must be x]
537 ** mxhosts -- a pointer to a return buffer of MX records.
538 ** mxprefs -- a pointer to a return buffer of MX preferences.
539 ** If NULL, don't try to populate.
540 ** flags -- flags:
541 ** DROPLOCALHOSt -- If true, all MX records less preferred
542 ** than the local host (as determined by $=w) will
543 ** be discarded.
544 ** TRYFALLBACK -- add also fallback MX host?
545 ** ISAD -- host lookup was secure?
546 ** rcode -- a pointer to an EX_ status code.
547 ** pttl -- pointer to return TTL (can be NULL).
548 **
549 ** Returns:
550 ** The number of MX records found.
551 ** -1 if there is an internal failure.
552 ** If no MX records are found, mxhosts[0] is set to host
553 ** and 1 is returned.
554 **
555 ** Side Effects:
556 ** The entries made for mxhosts point to a static array
557 ** MXHostBuf[MXHOSTBUFSIZE], so the data needs to be copied,
558 ** if it must be preserved across calls to this function.
559 */
560
561 int
getmxrr(host,mxhosts,mxprefs,flags,rcode,pttl,port)562 getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
563 char *host;
564 char **mxhosts;
565 unsigned short *mxprefs;
566 unsigned int flags;
567 int *rcode;
568 int *pttl;
569 int port;
570 {
571 register unsigned char *eom, *cp;
572 register int i, j, n;
573 int nmx = 0;
574 register char *bp;
575 HEADER *hp;
576 querybuf answer;
577 int ancount, qdcount, buflen;
578 bool seenlocal = false;
579 unsigned short pref, type;
580 unsigned short localpref = 256;
581 char *fallbackMX = FallbackMX;
582 bool trycanon = false;
583 unsigned short *prefs;
584 int (*resfunc) __P((const char *, int, int, u_char *, int));
585 unsigned short prefer[MAXMXHOSTS];
586 int weight[MAXMXHOSTS];
587 int ttl = 0;
588 bool ad;
589 bool seennullmx = false;
590 extern int res_query __P((const char *, int, int, u_char *, int));
591 extern int res_search __P((const char *, int, int , u_char *, int));
592 # if DANE
593 bool cname2mx;
594 char qname[MAXNAME]; /* EAI: copy of host: ok? */
595 unsigned long old_options = 0;
596 # endif
597
598 if (tTd(8, 2))
599 sm_dprintf("getmxrr(%s, droplocalhost=%d, flags=%X, port=%d)\n",
600 host, (flags & DROPLOCALHOST) != 0, flags, port);
601 ad = (flags & ISAD) != 0;
602 *rcode = EX_OK;
603 if (pttl != NULL)
604 *pttl = SM_DEFAULT_TTL;
605 if (*host == '\0')
606 return 0;
607 # if DANE
608 cname2mx = false;
609 qname[0] = '\0';
610 old_options = _res.options;
611 if (ad)
612 _res.options |= SM_RES_DNSSEC;
613 # endif
614
615 if ((fallbackMX != NULL && (flags & DROPLOCALHOST) != 0 &&
616 wordinclass(fallbackMX, 'w')) || (flags & TRYFALLBACK) == 0)
617 {
618 /* don't use fallback for this pass */
619 fallbackMX = NULL;
620 }
621
622 if (mxprefs != NULL)
623 prefs = mxprefs;
624 else
625 prefs = prefer;
626
627 /* efficiency hack -- numeric or non-MX lookups */
628 if (host[0] == '[')
629 goto punt;
630
631 # if DANE
632 /*
633 ** NOTE: This only works if nocanonify is used,
634 ** otherwise the name is already rewritten.
635 */
636
637 /* always or only when "needed"? */
638 if (DANE_ALWAYS == Dane || (ad && DANE_SECURE == Dane))
639 (void) sm_strlcpy(qname, host, sizeof(qname));
640 # endif /* DANE */
641
642 # if USE_EAI
643 if (!addr_is_ascii(host))
644 {
645 /* XXX memory leak? */
646 host = sm_rpool_strdup_x(CurEnv->e_rpool, hn2alabel(host));
647 }
648 # endif /* USE_EAI */
649
650 /*
651 ** If we don't have MX records in our host switch, don't
652 ** try for MX records. Note that this really isn't "right",
653 ** since we might be set up to try NIS first and then DNS;
654 ** if the host is found in NIS we really shouldn't be doing
655 ** MX lookups. However, that should be a degenerate case.
656 */
657
658 if (!UseNameServer)
659 goto punt;
660 if (HasWildcardMX && ConfigLevel >= 6)
661 resfunc = res_query;
662 else
663 resfunc = res_search;
664 # if DNSSEC_TEST
665 if (tTd(8, 110))
666 resfunc = tstdns_search;
667 # endif
668
669 errno = 0;
670 hp = (HEADER *)&answer;
671 n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer,
672 sizeof(answer));
673 if (n < 0)
674 {
675 if (tTd(8, 1))
676 # if DNSSEC_TEST
677 sm_dprintf("getmxrr: res_search(%s) failed (errno=%d (%s), h_errno=%d (%s))\n",
678 host, errno, strerror(errno),
679 h_errno, herrno2txt(h_errno));
680 # else
681 sm_dprintf("getmxrr: res_search(%s) failed, h_errno=%d\n",
682 host, h_errno);
683 # endif
684 switch (h_errno)
685 {
686 case NO_DATA:
687 trycanon = true;
688 /* FALLTHROUGH */
689
690 case NO_RECOVERY:
691 /* no MX data on this host */
692 goto punt;
693
694 case HOST_NOT_FOUND:
695 # if BROKEN_RES_SEARCH
696 case 0: /* Ultrix resolver returns failure w/ h_errno=0 */
697 # endif
698 /* host doesn't exist in DNS; might be in /etc/hosts */
699 trycanon = true;
700 *rcode = EX_NOHOST;
701 goto punt;
702
703 case TRY_AGAIN:
704 case -1:
705 /* couldn't connect to the name server */
706 if (fallbackMX != NULL)
707 {
708 /* name server is hosed -- push to fallback */
709 nmx = fallbackmxrr(nmx, prefs, mxhosts);
710 goto done;
711 }
712 /* it might come up later; better queue it up */
713 *rcode = EX_TEMPFAIL;
714 break;
715
716 default:
717 syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)",
718 host, h_errno);
719 *rcode = EX_OSERR;
720 break;
721 }
722
723 /* irreconcilable differences */
724 goto error;
725 }
726
727 ad = ad && hp->ad;
728 if (tTd(8, 2))
729 sm_dprintf("getmxrr(%s), hp=%p, ad=%d\n", host, (void*)hp, ad);
730
731 /* avoid problems after truncation in tcp packets */
732 if (n > sizeof(answer))
733 n = sizeof(answer);
734
735 /* find first satisfactory answer */
736 cp = (unsigned char *)&answer + HFIXEDSZ;
737 eom = (unsigned char *)&answer + n;
738
739 for (qdcount = ntohs((unsigned short) hp->qdcount);
740 qdcount--;
741 cp += n + QFIXEDSZ)
742 {
743 if ((n = dn_skipname(cp, eom)) < 0)
744 goto punt;
745 }
746
747 /* NOTE: see definition of MXHostBuf! */
748 buflen = sizeof(MXHostBuf) - 1;
749 SM_ASSERT(buflen > 0);
750 bp = MXHostBuf;
751 ancount = ntohs((unsigned short) hp->ancount);
752
753 /* See RFC 1035 for layout of RRs. */
754 /* XXX leave room for FallbackMX ? */
755 while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
756 {
757 if ((n = dn_expand((unsigned char *)&answer, eom, cp,
758 (RES_UNC_T) bp, buflen)) < 0)
759 break;
760 cp += n;
761 GETSHORT(type, cp);
762 cp += INT16SZ; /* skip over class */
763 GETLONG(ttl, cp);
764 GETSHORT(n, cp); /* rdlength */
765 # if DANE
766 if (type == T_CNAME)
767 cname2mx = true;
768 # endif
769 if (type != T_MX)
770 {
771 if ((tTd(8, 8) || _res.options & RES_DEBUG)
772 # if DANE
773 && type != T_RRSIG
774 # endif
775 )
776 sm_dprintf("unexpected answer type %s, size %d\n",
777 dns_type_to_string(type), n);
778 cp += n;
779 continue;
780 }
781 GETSHORT(pref, cp);
782 if ((n = dn_expand((unsigned char *)&answer, eom, cp,
783 (RES_UNC_T) bp, buflen)) < 0)
784 break;
785 cp += n;
786 n = strlen(bp);
787
788 /* Support for RFC7505 "MX 0 ." */
789 if (pref == 0 && *bp == '\0')
790 seennullmx = true;
791
792 if (wordinclass(bp, 'w'))
793 {
794 if (tTd(8, 3))
795 sm_dprintf("found localhost (%s) in MX list, pref=%d\n",
796 bp, pref);
797 if ((flags & DROPLOCALHOST) != 0)
798 {
799 if (!seenlocal || pref < localpref)
800 localpref = pref;
801 seenlocal = true;
802 continue;
803 }
804 weight[nmx] = 0;
805 }
806 else
807 weight[nmx] = mxrand(bp);
808 prefs[nmx] = pref;
809 mxhosts[nmx++] = bp;
810 # if DANE
811 if (CHK_DANE(Dane) && port >= 0)
812 {
813 int nrr;
814 unsigned long flags;
815
816 flags = ad ? TLSAFLADMX : TLSAFLNOADMX;
817 nrr = gettlsa(bp, NULL, NULL, flags, ttl, port);
818
819 /* Only check qname if no TLSA RRs were found */
820 if (0 == nrr && cname2mx && '\0' != qname[0] &&
821 strcmp(qname, bp))
822 gettlsa(qname, bp, NULL, flags, ttl, port);
823 /* XXX is this the right ad flag? */
824 }
825 # endif
826
827 /*
828 ** Note: n can be 0 for something like:
829 ** host MX 0 .
830 ** See RFC 7505
831 */
832
833 bp += n;
834 if (0 == n || bp[-1] != '.')
835 {
836 *bp++ = '.';
837 n++;
838 }
839 *bp++ = '\0';
840 if (buflen < n + 1)
841 {
842 /* don't want to wrap buflen */
843 break;
844 }
845 buflen -= n + 1;
846 }
847
848 /* Support for RFC7505 "MX 0 ." */
849 if (seennullmx && nmx == 1)
850 {
851 if (tTd(8, 4))
852 sm_dprintf("getmxrr: Null MX record found, domain doesn't accept mail (RFC7505)\n");
853 *rcode = EX_UNAVAILABLE;
854 return NULLMX;
855 }
856
857 /* return only one TTL entry, that should be sufficient */
858 if (ttl > 0 && pttl != NULL)
859 *pttl = ttl;
860
861 /* sort the records */
862 for (i = 0; i < nmx; i++)
863 {
864 for (j = i + 1; j < nmx; j++)
865 {
866 if (prefs[i] > prefs[j] ||
867 (prefs[i] == prefs[j] && weight[i] > weight[j]))
868 {
869 register int temp;
870 register char *temp1;
871
872 temp = prefs[i];
873 prefs[i] = prefs[j];
874 prefs[j] = temp;
875 temp1 = mxhosts[i];
876 mxhosts[i] = mxhosts[j];
877 mxhosts[j] = temp1;
878 temp = weight[i];
879 weight[i] = weight[j];
880 weight[j] = temp;
881 }
882 }
883 if (seenlocal && prefs[i] >= localpref)
884 {
885 /* truncate higher preference part of list */
886 nmx = i;
887 }
888 }
889
890 /* delete duplicates from list (yes, some bozos have duplicates) */
891 for (i = 0; i < nmx - 1; )
892 {
893 if (!SM_STRCASEEQ(mxhosts[i], mxhosts[i + 1]))
894 i++;
895 else
896 {
897 /* compress out duplicate */
898 for (j = i + 1; j < nmx; j++)
899 {
900 mxhosts[j] = mxhosts[j + 1];
901 prefs[j] = prefs[j + 1];
902 }
903 nmx--;
904 }
905 }
906
907 if (nmx == 0)
908 {
909 punt:
910 if (seenlocal)
911 {
912 struct hostent *h = NULL;
913
914 /*
915 ** If we have deleted all MX entries, this is
916 ** an error -- we should NEVER send to a host that
917 ** has an MX, and this should have been caught
918 ** earlier in the config file.
919 **
920 ** Some sites prefer to go ahead and try the
921 ** A record anyway; that case is handled by
922 ** setting TryNullMXList. I believe this is a
923 ** bad idea, but it's up to you....
924 */
925
926 if (TryNullMXList)
927 {
928 SM_SET_H_ERRNO(0);
929 errno = 0;
930 h = sm_gethostbyname(host, AF_INET);
931 if (h == NULL)
932 {
933 if (errno == ETIMEDOUT ||
934 h_errno == TRY_AGAIN ||
935 (errno == ECONNREFUSED &&
936 UseNameServer))
937 {
938 *rcode = EX_TEMPFAIL;
939 goto error;
940 }
941 # if NETINET6
942 SM_SET_H_ERRNO(0);
943 errno = 0;
944 h = sm_gethostbyname(host, AF_INET6);
945 if (h == NULL &&
946 (errno == ETIMEDOUT ||
947 h_errno == TRY_AGAIN ||
948 (errno == ECONNREFUSED &&
949 UseNameServer)))
950 {
951 *rcode = EX_TEMPFAIL;
952 goto error;
953 }
954 # endif /* NETINET6 */
955 }
956 }
957
958 if (h == NULL)
959 {
960 *rcode = EX_CONFIG;
961 syserr("MX list for %s points back to %s",
962 host, MyHostName);
963 goto error;
964 }
965 # if NETINET6
966 freehostent(h);
967 h = NULL;
968 # endif
969 }
970 if (strlen(host) >= sizeof(MXHostBuf))
971 {
972 *rcode = EX_CONFIG;
973 syserr("Host name %s too long",
974 shortenstring(host, MAXSHORTSTR));
975 goto error;
976 }
977 (void) sm_strlcpy(MXHostBuf, host, sizeof(MXHostBuf));
978 mxhosts[0] = MXHostBuf;
979 prefs[0] = 0;
980 if (host[0] == '[')
981 {
982 register char *p;
983 # if NETINET6
984 struct sockaddr_in6 tmp6;
985 # endif
986
987 /* this may be an MX suppression-style address */
988 p = strchr(MXHostBuf, ']');
989 if (p != NULL)
990 {
991 *p = '\0';
992
993 if (inet_addr(&MXHostBuf[1]) != INADDR_NONE)
994 {
995 nmx++;
996 *p = ']';
997 }
998 # if NETINET6
999 else if (anynet_pton(AF_INET6, &MXHostBuf[1],
1000 &tmp6.sin6_addr) == 1)
1001 {
1002 nmx++;
1003 *p = ']';
1004 }
1005 # endif /* NETINET6 */
1006 else
1007 {
1008 # if USE_EAI
1009 char *hn;
1010
1011 hn = MXHostBuf + 1;
1012 if (!addr_is_ascii(hn))
1013 {
1014 const char *ahn;
1015
1016 ahn = hn2alabel(hn);
1017 if (strlen(ahn) >= sizeof(MXHostBuf) - 1)
1018 {
1019 *rcode = EX_CONFIG;
1020 syserr("Encoded host name %s too long",
1021 shortenstring(ahn, MAXSHORTSTR));
1022 goto error;
1023 }
1024 (void) sm_strlcpy(hn, ahn, sizeof(MXHostBuf) - 1);
1025 }
1026 # endif /* USE_EAI */
1027 trycanon = true;
1028 mxhosts[0]++;
1029 }
1030 }
1031 }
1032 if (trycanon &&
1033 (n = getcanonname(mxhosts[0], sizeof(MXHostBuf) - 2, false,
1034 pttl)) != HOST_NOTFOUND)
1035 {
1036 /* XXX MXHostBuf == "" ? is that possible? */
1037 bp = &MXHostBuf[strlen(MXHostBuf)];
1038 if (bp[-1] != '.')
1039 {
1040 *bp++ = '.';
1041 *bp = '\0';
1042 }
1043 nmx = 1;
1044 # if DANE
1045 if (tTd(8, 3))
1046 sm_dprintf("getmxrr=%s, getcanonname=%d\n",
1047 mxhosts[0], n);
1048 if (CHK_DANE(Dane) && port >= 0)
1049 {
1050 int nrr;
1051 unsigned long flags;
1052 unsigned int cttl;
1053
1054 if (pttl != NULL)
1055 cttl = *pttl;
1056 else if (ttl > 0)
1057 cttl = ttl;
1058 else
1059 cttl = SM_DEFAULT_TTL;
1060
1061 flags = (ad && n == HOST_SECURE)
1062 ? TLSAFLADMX : TLSAFLNOADMX;
1063 nrr = gettlsa(mxhosts[0], NULL, NULL, flags,
1064 cttl, port);
1065
1066 /*
1067 ** Only check qname if no TLSA RRs were found
1068 ** XXX: what about (temp) DNS errors?
1069 */
1070
1071 if (0 == nrr && '\0' != qname[0] &&
1072 strcmp(qname, mxhosts[0]))
1073 gettlsa(qname, mxhosts[0], NULL, flags,
1074 cttl, port);
1075 /* XXX is this the right ad flag? */
1076 }
1077 # endif
1078 }
1079 }
1080
1081 /* if we have a default lowest preference, include that */
1082 if (fallbackMX != NULL && !seenlocal)
1083 {
1084 /* TODO: DNSsec status of fallbacks */
1085 nmx = fallbackmxrr(nmx, prefs, mxhosts);
1086 }
1087 done:
1088 # if DANE
1089 _res.options = old_options;
1090 # endif
1091 return nmx;
1092
1093 error:
1094 # if DANE
1095 _res.options = old_options;
1096 # endif
1097 return -1;
1098 }
1099
1100 /*
1101 ** MXRAND -- create a randomizer for equal MX preferences
1102 **
1103 ** If two MX hosts have equal preferences we want to randomize
1104 ** the selection. But in order for signatures to be the same,
1105 ** we need to randomize the same way each time. This function
1106 ** computes a pseudo-random hash function from the host name.
1107 **
1108 ** Parameters:
1109 ** host -- the name of the host.
1110 **
1111 ** Returns:
1112 ** A random but repeatable value based on the host name.
1113 */
1114
1115 static int
mxrand(host)1116 mxrand(host)
1117 register char *host;
1118 {
1119 int hfunc;
1120 static unsigned int seed;
1121
1122 if (seed == 0)
1123 {
1124 seed = (int) curtime() & 0xffff;
1125 if (seed == 0)
1126 seed++;
1127 }
1128
1129 if (tTd(17, 9))
1130 sm_dprintf("mxrand(%s)", host);
1131
1132 hfunc = seed;
1133 while (*host != '\0')
1134 {
1135 int c = *host++;
1136
1137 if (isascii(c) && isupper(c))
1138 c = tolower(c);
1139 hfunc = ((hfunc << 1) ^ c) % 2003;
1140 }
1141
1142 hfunc &= 0xff;
1143 hfunc++;
1144
1145 if (tTd(17, 9))
1146 sm_dprintf(" = %d\n", hfunc);
1147 return hfunc;
1148 }
1149 /*
1150 ** BESTMX -- find the best MX for a name
1151 **
1152 ** This is really a hack, but I don't see any obvious way
1153 ** to generalize it at the moment.
1154 */
1155
1156 /* ARGSUSED3 */
1157 char *
bestmx_map_lookup(map,name,av,statp)1158 bestmx_map_lookup(map, name, av, statp)
1159 MAP *map;
1160 char *name;
1161 char **av;
1162 int *statp;
1163 {
1164 int nmx;
1165 int saveopts = _res.options;
1166 int i;
1167 ssize_t len = 0;
1168 char *result;
1169 char *mxhosts[MAXMXHOSTS + 1];
1170 # if _FFR_BESTMX_BETTER_TRUNCATION
1171 char *buf;
1172 # else
1173 char *p;
1174 char buf[PSBUFSIZE / 2];
1175 # endif
1176
1177 _res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
1178 nmx = getmxrr(name, mxhosts, NULL, 0, statp, NULL, -1);
1179 _res.options = saveopts;
1180 if (nmx <= 0)
1181 return NULL;
1182 if (bitset(MF_MATCHONLY, map->map_mflags))
1183 return map_rewrite(map, name, strlen(name), NULL);
1184 if ((map->map_coldelim == '\0') || (nmx == 1))
1185 return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
1186
1187 /*
1188 ** We were given a -z flag (return all MXs) and there are multiple
1189 ** ones. We need to build them all into a list.
1190 */
1191
1192 # if _FFR_BESTMX_BETTER_TRUNCATION
1193 for (i = 0; i < nmx; i++)
1194 {
1195 if (strchr(mxhosts[i], map->map_coldelim) != NULL)
1196 {
1197 syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
1198 mxhosts[i], map->map_coldelim);
1199 return NULL;
1200 }
1201 len += strlen(mxhosts[i]) + 1;
1202 if (len < 0)
1203 {
1204 len -= strlen(mxhosts[i]) + 1;
1205 break;
1206 }
1207 }
1208 buf = (char *) sm_malloc(len);
1209 if (buf == NULL)
1210 {
1211 *statp = EX_UNAVAILABLE;
1212 return NULL;
1213 }
1214 *buf = '\0';
1215 for (i = 0; i < nmx; i++)
1216 {
1217 int end;
1218
1219 end = sm_strlcat(buf, mxhosts[i], len);
1220 if (i != nmx && end + 1 < len)
1221 {
1222 buf[end] = map->map_coldelim;
1223 buf[end + 1] = '\0';
1224 }
1225 }
1226
1227 /* Cleanly truncate for rulesets */
1228 truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim);
1229 # else /* _FFR_BESTMX_BETTER_TRUNCATION */
1230 p = buf;
1231 for (i = 0; i < nmx; i++)
1232 {
1233 size_t slen;
1234
1235 if (strchr(mxhosts[i], map->map_coldelim) != NULL)
1236 {
1237 syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
1238 mxhosts[i], map->map_coldelim);
1239 return NULL;
1240 }
1241 slen = strlen(mxhosts[i]);
1242 if (len + slen + 2 > sizeof(buf))
1243 break;
1244 if (i > 0)
1245 {
1246 *p++ = map->map_coldelim;
1247 len++;
1248 }
1249 (void) sm_strlcpy(p, mxhosts[i], sizeof(buf) - len);
1250 p += slen;
1251 len += slen;
1252 }
1253 # endif /* _FFR_BESTMX_BETTER_TRUNCATION */
1254
1255 result = map_rewrite(map, buf, len, av);
1256 # if _FFR_BESTMX_BETTER_TRUNCATION
1257 sm_free(buf);
1258 # endif
1259 return result;
1260 }
1261 /*
1262 ** DNS_GETCANONNAME -- get the canonical name for named host using DNS
1263 **
1264 ** This algorithm tries to be smart about wildcard MX records.
1265 ** This is hard to do because DNS doesn't tell is if we matched
1266 ** against a wildcard or a specific MX.
1267 **
1268 ** We always prefer A & CNAME records, since these are presumed
1269 ** to be specific.
1270 **
1271 ** If we match an MX in one pass and lose it in the next, we use
1272 ** the old one. For example, consider an MX matching *.FOO.BAR.COM.
1273 ** A hostname bletch.foo.bar.com will match against this MX, but
1274 ** will stop matching when we try bletch.bar.com -- so we know
1275 ** that bletch.foo.bar.com must have been right. This fails if
1276 ** there was also an MX record matching *.BAR.COM, but there are
1277 ** some things that just can't be fixed.
1278 **
1279 ** Parameters:
1280 ** host -- a buffer containing the name of the host.
1281 ** This is a value-result parameter.
1282 ** hbsize -- the size of the host buffer.
1283 ** trymx -- if set, try MX records as well as A and CNAME.
1284 ** statp -- pointer to place to store status.
1285 ** pttl -- pointer to return TTL (can be NULL).
1286 **
1287 ** Returns:
1288 ** >0 -- if the host was found.
1289 ** 0 -- otherwise.
1290 */
1291
1292 int
dns_getcanonname(host,hbsize,trymx,statp,pttl)1293 dns_getcanonname(host, hbsize, trymx, statp, pttl)
1294 char *host;
1295 int hbsize;
1296 bool trymx;
1297 int *statp;
1298 int *pttl;
1299 {
1300 register unsigned char *eom, *ap;
1301 register char *cp;
1302 register int n;
1303 HEADER *hp;
1304 querybuf answer;
1305 int ancount, qdcount, ret, type, qtype, initial, loopcnt, ttl, sli;
1306 char **domain;
1307 char *dp;
1308 char *mxmatch;
1309 bool amatch, gotmx, ad;
1310 char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)];
1311 # if DNSSEC_TEST
1312 # define ADDSL 1 /* NameSearchList may add another entry to searchlist! */
1313 # else
1314 # define ADDSL 0
1315 # endif
1316 char *searchlist[MAXDNSRCH + 2 + ADDSL];
1317 # define SLSIZE SM_ARRAY_SIZE(searchlist)
1318 int (*resqdomain) __P((const char *, const char *, int, int, unsigned char *, int));
1319 # if DANE
1320 unsigned long old_options = 0;
1321 # endif
1322
1323 ttl = 0;
1324 gotmx = false;
1325 ad = true;
1326 if (tTd(8, 2))
1327 sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
1328
1329 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
1330 {
1331 *statp = EX_UNAVAILABLE;
1332 return HOST_NOTFOUND;
1333 }
1334
1335 # if DANE
1336 old_options = _res.options;
1337 if (DANE_SECURE == Dane)
1338 _res.options |= SM_RES_DNSSEC;
1339 # endif
1340
1341 *statp = EX_OK;
1342 resqdomain = res_querydomain;
1343 # if DNSSEC_TEST
1344 if (tTd(8, 110))
1345 resqdomain = tstdns_querydomain;
1346 # endif
1347
1348 /*
1349 ** Initialize domain search list. If there is at least one
1350 ** dot in the name, search the unmodified name first so we
1351 ** find "vse.CS" in Czechoslovakia instead of in the local
1352 ** domain (e.g., vse.CS.Berkeley.EDU). Note that there is no
1353 ** longer a country named Czechoslovakia but this type of problem
1354 ** is still present.
1355 **
1356 ** Older versions of the resolver could create this
1357 ** list by tearing apart the host name.
1358 */
1359
1360 loopcnt = 0;
1361 cnameloop:
1362 /* Check for dots in the name */
1363 for (cp = host, n = 0; *cp != '\0'; cp++)
1364 if (*cp == '.')
1365 n++;
1366
1367 /*
1368 ** Build the search list.
1369 ** If there is at least one dot in name, start with a null
1370 ** domain to search the unmodified name first.
1371 ** If name does not end with a dot and search up local domain
1372 ** tree desired, append each local domain component to the
1373 ** search list; if name contains no dots and default domain
1374 ** name is desired, append default domain name to search list;
1375 ** else if name ends in a dot, remove that dot.
1376 */
1377
1378 sli = 0;
1379 if (n > 0)
1380 searchlist[sli++] = "";
1381 # if DNSSEC_TEST
1382 if (NameSearchList != NULL)
1383 {
1384 SM_ASSERT(sli < SLSIZE);
1385 searchlist[sli++] = NameSearchList;
1386 }
1387 # endif
1388 if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options))
1389 {
1390 /* make sure there are less than MAXDNSRCH domains */
1391 for (domain = RES_DNSRCH_VARIABLE, ret = 0;
1392 *domain != NULL && ret < MAXDNSRCH && sli < SLSIZE;
1393 ret++)
1394 searchlist[sli++] = *domain++;
1395 }
1396 else if (n == 0 && bitset(RES_DEFNAMES, _res.options))
1397 {
1398 SM_ASSERT(sli < SLSIZE);
1399 searchlist[sli++] = _res.defdname;
1400 }
1401 else if (*cp == '.')
1402 {
1403 *cp = '\0';
1404 }
1405 SM_ASSERT(sli < SLSIZE);
1406 searchlist[sli] = NULL;
1407
1408 /*
1409 ** Now loop through the search list, appending each domain in turn
1410 ** name and searching for a match.
1411 */
1412
1413 mxmatch = NULL;
1414 initial = T_A;
1415 # if NETINET6
1416 if (InetMode == AF_INET6)
1417 initial = T_AAAA;
1418 # endif
1419 qtype = initial;
1420
1421 for (sli = 0; sli < SLSIZE; )
1422 {
1423 dp = searchlist[sli];
1424 if (NULL == dp)
1425 break;
1426 if (qtype == initial)
1427 gotmx = false;
1428 if (tTd(8, 5))
1429 sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n",
1430 host, dp,
1431 # if NETINET6
1432 qtype == T_AAAA ? "AAAA" :
1433 # endif
1434 qtype == T_A ? "A" :
1435 qtype == T_MX ? "MX" :
1436 "???");
1437 errno = 0;
1438 hp = (HEADER *) &answer;
1439 ret = (*resqdomain)(host, dp, C_IN, qtype,
1440 answer.qb2, sizeof(answer.qb2));
1441 if (ret <= 0)
1442 {
1443 int save_errno = errno;
1444
1445 if (tTd(8, 7))
1446 sm_dprintf("\tNO: errno=%d, h_errno=%d\n",
1447 save_errno, h_errno);
1448
1449 if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN)
1450 {
1451 /*
1452 ** the name server seems to be down or broken.
1453 */
1454
1455 SM_SET_H_ERRNO(TRY_AGAIN);
1456 if (*dp == '\0')
1457 {
1458 if (*statp == EX_OK)
1459 *statp = EX_TEMPFAIL;
1460 goto nexttype;
1461 }
1462 *statp = EX_TEMPFAIL;
1463
1464 if (WorkAroundBrokenAAAA)
1465 {
1466 /*
1467 ** Only return if not TRY_AGAIN as an
1468 ** attempt with a different qtype may
1469 ** succeed (res_querydomain() calls
1470 ** res_query() calls res_send() which
1471 ** sets errno to ETIMEDOUT if the
1472 ** nameservers could be contacted but
1473 ** didn't give an answer).
1474 */
1475
1476 if (save_errno != ETIMEDOUT)
1477 goto error;
1478 }
1479 else
1480 goto error;
1481 }
1482
1483 nexttype:
1484 if (h_errno != HOST_NOT_FOUND)
1485 {
1486 /* might have another type of interest */
1487 # if NETINET6
1488 if (qtype == T_AAAA)
1489 {
1490 qtype = T_A;
1491 continue;
1492 }
1493 else
1494 # endif /* NETINET6 */
1495 if (qtype == T_A && !gotmx &&
1496 (trymx || *dp == '\0'))
1497 {
1498 qtype = T_MX;
1499 continue;
1500 }
1501 }
1502
1503 /* definite no -- try the next domain */
1504 sli++;
1505 qtype = initial;
1506 continue;
1507 }
1508 else if (tTd(8, 7))
1509 sm_dprintf("\tYES\n");
1510
1511 /* avoid problems after truncation in tcp packets */
1512 if (ret > sizeof(answer))
1513 ret = sizeof(answer);
1514 SM_ASSERT(ret >= 0);
1515
1516 /*
1517 ** Appear to have a match. Confirm it by searching for A or
1518 ** CNAME records. If we don't have a local domain
1519 ** wild card MX record, we will accept MX as well.
1520 */
1521
1522 ap = (unsigned char *) &answer + HFIXEDSZ;
1523 eom = (unsigned char *) &answer + ret;
1524
1525 if (0 == hp->ad)
1526 ad = false;
1527
1528 /* skip question part of response -- we know what we asked */
1529 for (qdcount = ntohs((unsigned short) hp->qdcount);
1530 qdcount--;
1531 ap += ret + QFIXEDSZ)
1532 {
1533 if ((ret = dn_skipname(ap, eom)) < 0)
1534 {
1535 if (tTd(8, 20))
1536 sm_dprintf("qdcount failure (%d)\n",
1537 ntohs((unsigned short) hp->qdcount));
1538 *statp = EX_SOFTWARE;
1539 goto error;
1540 }
1541 }
1542
1543 amatch = false;
1544 for (ancount = ntohs((unsigned short) hp->ancount);
1545 --ancount >= 0 && ap < eom;
1546 ap += n)
1547 {
1548 n = dn_expand((unsigned char *) &answer, eom, ap,
1549 (RES_UNC_T) nbuf, sizeof(nbuf));
1550 if (n < 0)
1551 break;
1552 ap += n;
1553 GETSHORT(type, ap);
1554 ap += INT16SZ; /* skip over class */
1555 GETLONG(ttl, ap);
1556 GETSHORT(n, ap); /* rdlength */
1557 switch (type)
1558 {
1559 case T_MX:
1560 gotmx = true;
1561 if (*dp != '\0' && HasWildcardMX)
1562 {
1563 /*
1564 ** If we are using MX matches and have
1565 ** not yet gotten one, save this one
1566 ** but keep searching for an A or
1567 ** CNAME match.
1568 */
1569
1570 if (trymx && mxmatch == NULL)
1571 mxmatch = dp;
1572 continue;
1573 }
1574
1575 /*
1576 ** If we did not append a domain name, this
1577 ** must have been a canonical name to start
1578 ** with. Even if we did append a domain name,
1579 ** in the absence of a wildcard MX this must
1580 ** still be a real MX match.
1581 ** Such MX matches are as good as an A match,
1582 ** fall through.
1583 */
1584 /* FALLTHROUGH */
1585
1586 # if NETINET6
1587 case T_AAAA:
1588 # endif
1589 case T_A:
1590 /* Flag that a good match was found */
1591 amatch = true;
1592
1593 /* continue in case a CNAME also exists */
1594 continue;
1595
1596 case T_CNAME:
1597 if (DontExpandCnames)
1598 {
1599 /* got CNAME -- guaranteed canonical */
1600 amatch = true;
1601 break;
1602 }
1603
1604 if (loopcnt++ > MAXCNAMEDEPTH)
1605 {
1606 /*XXX should notify postmaster XXX*/
1607 message("DNS failure: CNAME loop for %s",
1608 host);
1609 if (CurEnv->e_message == NULL)
1610 {
1611 char ebuf[MAXLINE];
1612
1613 (void) sm_snprintf(ebuf,
1614 sizeof(ebuf),
1615 "Deferred: DNS failure: CNAME loop for %.100s",
1616 host);
1617 CurEnv->e_message =
1618 sm_rpool_strdup_x(
1619 CurEnv->e_rpool, ebuf);
1620 }
1621 SM_SET_H_ERRNO(NO_RECOVERY);
1622 *statp = EX_CONFIG;
1623 goto error;
1624 }
1625
1626 /* value points at name */
1627 if ((ret = dn_expand((unsigned char *)&answer,
1628 eom, ap, (RES_UNC_T) nbuf,
1629 sizeof(nbuf))) < 0)
1630 break;
1631 (void) sm_strlcpy(host, nbuf, hbsize);
1632
1633 /*
1634 ** RFC 1034 section 3.6 specifies that CNAME
1635 ** should point at the canonical name -- but
1636 ** urges software to try again anyway.
1637 */
1638
1639 goto cnameloop;
1640
1641 default:
1642 /* not a record of interest */
1643 continue;
1644 }
1645 }
1646
1647 if (amatch)
1648 {
1649 /*
1650 ** Got a good match -- either an A, CNAME, or an
1651 ** exact MX record. Save it and get out of here.
1652 */
1653
1654 mxmatch = dp;
1655 break;
1656 }
1657
1658 /*
1659 ** Nothing definitive yet.
1660 ** If this was a T_A query and we haven't yet found a MX
1661 ** match, try T_MX if allowed to do so.
1662 ** Otherwise, try the next domain.
1663 */
1664
1665 # if NETINET6
1666 if (qtype == T_AAAA)
1667 qtype = T_A;
1668 else
1669 # endif
1670 if (qtype == T_A && !gotmx && (trymx || *dp == '\0'))
1671 qtype = T_MX;
1672 else
1673 {
1674 qtype = initial;
1675 sli++;
1676 }
1677 }
1678
1679 /* if nothing was found, we are done */
1680 if (mxmatch == NULL)
1681 {
1682 if (*statp == EX_OK)
1683 *statp = EX_NOHOST;
1684 goto error;
1685 }
1686
1687 /*
1688 ** Create canonical name and return.
1689 ** If saved domain name is null, name was already canonical.
1690 ** Otherwise append the saved domain name.
1691 */
1692
1693 (void) sm_snprintf(nbuf, sizeof(nbuf), "%.*s%s%.*s", MAXDNAME, host,
1694 *mxmatch == '\0' ? "" : ".",
1695 MAXDNAME, mxmatch);
1696 (void) sm_strlcpy(host, nbuf, hbsize);
1697 if (tTd(8, 5))
1698 sm_dprintf("dns_getcanonname: %s\n", host);
1699 *statp = EX_OK;
1700
1701 /* return only one TTL entry, that should be sufficient */
1702 if (ttl > 0 && pttl != NULL)
1703 *pttl = ttl;
1704 # if DANE
1705 _res.options = old_options;
1706 # endif
1707 return ad ? HOST_SECURE : HOST_OK;
1708
1709 error:
1710 # if DANE
1711 _res.options = old_options;
1712 # endif
1713 return HOST_NOTFOUND;
1714 }
1715
1716 #endif /* NAMED_BIND */
1717