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 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 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 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 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 * 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 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 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 * 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 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