domain.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:22k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1998, 1999 Sendmail, 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. #include <sendmail.h>
  14. #ifndef lint
  15. # if NAMED_BIND
  16. static char id[] = "@(#)$Id: domain.c,v 8.112 1999/10/13 04:15:40 ca Exp $ (with name server)";
  17. # else /* NAMED_BIND */
  18. static char id[] = "@(#)$Id: domain.c,v 8.112 1999/10/13 04:15:40 ca Exp $ (without name server)";
  19. # endif /* NAMED_BIND */
  20. #endif /* ! lint */
  21. #if NAMED_BIND
  22. # include <arpa/inet.h>
  23. /*
  24. **  The standard udp packet size PACKETSZ (512) is not sufficient for some
  25. **  nameserver answers containing very many resource records. The resolver
  26. **  may switch to tcp and retry if it detects udp packet overflow.
  27. **  Also note that the resolver routines res_query and res_search return
  28. **  the size of the *un*truncated answer in case the supplied answer buffer
  29. **  it not big enough to accommodate the entire answer.
  30. */
  31. # ifndef MAXPACKET
  32. #  define MAXPACKET 8192 /* max packet size used internally by BIND */
  33. # endif /* ! MAXPACKET */
  34. typedef union
  35. {
  36. HEADER qb1;
  37. u_char qb2[MAXPACKET];
  38. } querybuf;
  39. # ifndef MXHOSTBUFSIZE
  40. #  define MXHOSTBUFSIZE (128 * MAXMXHOSTS)
  41. # endif /* ! MXHOSTBUFSIZE */
  42. static char MXHostBuf[MXHOSTBUFSIZE];
  43. # ifndef MAXDNSRCH
  44. #  define MAXDNSRCH 6 /* number of possible domains to search */
  45. # endif /* ! MAXDNSRCH */
  46. # ifndef RES_DNSRCH_VARIABLE
  47. #  define RES_DNSRCH_VARIABLE _res.dnsrch
  48. # endif /* ! RES_DNSRCH_VARIABLE */
  49. # ifndef MAX
  50. #  define MAX(a, b) ((a) > (b) ? (a) : (b))
  51. # endif /* ! MAX */
  52. # ifndef NO_DATA
  53. #  define NO_DATA NO_ADDRESS
  54. # endif /* ! NO_DATA */
  55. # ifndef HFIXEDSZ
  56. #  define HFIXEDSZ 12 /* sizeof(HEADER) */
  57. # endif /* ! HFIXEDSZ */
  58. # define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */
  59. # if defined(__RES) && (__RES >= 19940415)
  60. #  define RES_UNC_T char *
  61. # else /* defined(__RES) && (__RES >= 19940415) */
  62. #  define RES_UNC_T u_char *
  63. # endif /* defined(__RES) && (__RES >= 19940415) */
  64. static char *gethostalias __P((char *));
  65. static int mxrand __P((char *));
  66. /*
  67. **  GETMXRR -- get MX resource records for a domain
  68. **
  69. ** Parameters:
  70. ** host -- the name of the host to MX.
  71. ** mxhosts -- a pointer to a return buffer of MX records.
  72. ** mxprefs -- a pointer to a return buffer of MX preferences.
  73. ** If NULL, don't try to populate.
  74. ** droplocalhost -- If TRUE, all MX records less preferred
  75. ** than the local host (as determined by $=w) will
  76. ** be discarded.
  77. ** rcode -- a pointer to an EX_ status code.
  78. **
  79. ** Returns:
  80. ** The number of MX records found.
  81. ** -1 if there is an internal failure.
  82. ** If no MX records are found, mxhosts[0] is set to host
  83. ** and 1 is returned.
  84. */
  85. int
  86. getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode)
  87. char *host;
  88. char **mxhosts;
  89. u_short *mxprefs;
  90. bool droplocalhost;
  91. int *rcode;
  92. {
  93. register u_char *eom, *cp;
  94. register int i, j, n;
  95. int nmx = 0;
  96. register char *bp;
  97. HEADER *hp;
  98. querybuf answer;
  99. int ancount, qdcount, buflen;
  100. bool seenlocal = FALSE;
  101. u_short pref, type;
  102. u_short localpref = 256;
  103. char *fallbackMX = FallBackMX;
  104. bool trycanon = FALSE;
  105. u_short *prefs;
  106. int (*resfunc)();
  107. u_short prefer[MAXMXHOSTS];
  108. int weight[MAXMXHOSTS];
  109. extern int res_query(), res_search();
  110. if (tTd(8, 2))
  111. dprintf("getmxrr(%s, droplocalhost=%d)n",
  112. host, droplocalhost);
  113. if (fallbackMX != NULL && droplocalhost &&
  114.     wordinclass(fallbackMX, 'w'))
  115. {
  116. /* don't use fallback for this pass */
  117. fallbackMX = NULL;
  118. }
  119. *rcode = EX_OK;
  120. if (mxprefs != NULL)
  121. prefs = mxprefs;
  122. else
  123. prefs = prefer;
  124. /* efficiency hack -- numeric or non-MX lookups */
  125. if (host[0] == '[')
  126. goto punt;
  127. /*
  128. **  If we don't have MX records in our host switch, don't
  129. **  try for MX records.  Note that this really isn't "right",
  130. **  since we might be set up to try NIS first and then DNS;
  131. **  if the host is found in NIS we really shouldn't be doing
  132. **  MX lookups.  However, that should be a degenerate case.
  133. */
  134. if (!UseNameServer)
  135. goto punt;
  136. if (HasWildcardMX && ConfigLevel >= 6)
  137. resfunc = res_query;
  138. else
  139. resfunc = res_search;
  140. errno = 0;
  141. n = (*resfunc)(host, C_IN, T_MX, (u_char *) &answer, sizeof(answer));
  142. if (n < 0)
  143. {
  144. if (tTd(8, 1))
  145. dprintf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)n",
  146.     (host == NULL) ? "<NULL>" : host, errno, h_errno);
  147. switch (h_errno)
  148. {
  149.   case NO_DATA:
  150. trycanon = TRUE;
  151. /* FALLTHROUGH */
  152.   case NO_RECOVERY:
  153. /* no MX data on this host */
  154. goto punt;
  155.   case HOST_NOT_FOUND:
  156. # if BROKEN_RES_SEARCH
  157.   case 0: /* Ultrix resolver retns failure w/ h_errno=0 */
  158. # endif /* BROKEN_RES_SEARCH */
  159. /* host doesn't exist in DNS; might be in /etc/hosts */
  160. trycanon = TRUE;
  161. *rcode = EX_NOHOST;
  162. goto punt;
  163.   case TRY_AGAIN:
  164.   case -1:
  165. /* couldn't connect to the name server */
  166. if (fallbackMX != NULL)
  167. {
  168. /* name server is hosed -- push to fallback */
  169. if (nmx > 0)
  170. prefs[nmx] = prefs[nmx - 1] + 1;
  171. else
  172. prefs[nmx] = 0;
  173. mxhosts[nmx++] = fallbackMX;
  174. return nmx;
  175. }
  176. /* it might come up later; better queue it up */
  177. *rcode = EX_TEMPFAIL;
  178. break;
  179.   default:
  180. syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)n",
  181. host, h_errno);
  182. *rcode = EX_OSERR;
  183. break;
  184. }
  185. /* irreconcilable differences */
  186. return -1;
  187. }
  188. /* avoid problems after truncation in tcp packets */
  189. if (n > sizeof(answer))
  190. n = sizeof(answer);
  191. /* find first satisfactory answer */
  192. hp = (HEADER *)&answer;
  193. cp = (u_char *)&answer + HFIXEDSZ;
  194. eom = (u_char *)&answer + n;
  195. for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
  196. if ((n = dn_skipname(cp, eom)) < 0)
  197. goto punt;
  198. buflen = sizeof(MXHostBuf) - 1;
  199. bp = MXHostBuf;
  200. ancount = ntohs(hp->ancount);
  201. while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
  202. {
  203. if ((n = dn_expand((u_char *)&answer,
  204.     eom, cp, (RES_UNC_T) bp, buflen)) < 0)
  205. break;
  206. cp += n;
  207. GETSHORT(type, cp);
  208. cp += INT16SZ + INT32SZ;
  209. GETSHORT(n, cp);
  210. if (type != T_MX)
  211. {
  212. if (tTd(8, 8) || _res.options & RES_DEBUG)
  213. dprintf("unexpected answer type %d, size %dn",
  214. type, n);
  215. cp += n;
  216. continue;
  217. }
  218. GETSHORT(pref, cp);
  219. if ((n = dn_expand((u_char *)&answer, eom, cp,
  220.    (RES_UNC_T) bp, buflen)) < 0)
  221. break;
  222. cp += n;
  223. if (wordinclass(bp, 'w'))
  224. {
  225. if (tTd(8, 3))
  226. dprintf("found localhost (%s) in MX list, pref=%dn",
  227. bp, pref);
  228. if (droplocalhost)
  229. {
  230. if (!seenlocal || pref < localpref)
  231. localpref = pref;
  232. seenlocal = TRUE;
  233. continue;
  234. }
  235. weight[nmx] = 0;
  236. }
  237. else
  238. weight[nmx] = mxrand(bp);
  239. prefs[nmx] = pref;
  240. mxhosts[nmx++] = bp;
  241. n = strlen(bp);
  242. bp += n;
  243. if (bp[-1] != '.')
  244. {
  245. *bp++ = '.';
  246. n++;
  247. }
  248. *bp++ = '';
  249. buflen -= n + 1;
  250. }
  251. /* sort the records */
  252. for (i = 0; i < nmx; i++)
  253. {
  254. for (j = i + 1; j < nmx; j++)
  255. {
  256. if (prefs[i] > prefs[j] ||
  257.     (prefs[i] == prefs[j] && weight[i] > weight[j]))
  258. {
  259. register int temp;
  260. register char *temp1;
  261. temp = prefs[i];
  262. prefs[i] = prefs[j];
  263. prefs[j] = temp;
  264. temp1 = mxhosts[i];
  265. mxhosts[i] = mxhosts[j];
  266. mxhosts[j] = temp1;
  267. temp = weight[i];
  268. weight[i] = weight[j];
  269. weight[j] = temp;
  270. }
  271. }
  272. if (seenlocal && prefs[i] >= localpref)
  273. {
  274. /* truncate higher preference part of list */
  275. nmx = i;
  276. }
  277. }
  278. /* delete duplicates from list (yes, some bozos have duplicates) */
  279. for (i = 0; i < nmx - 1; )
  280. {
  281. if (strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0)
  282. i++;
  283. else
  284. {
  285. /* compress out duplicate */
  286. for (j = i + 1; j < nmx; j++)
  287. {
  288. mxhosts[j] = mxhosts[j + 1];
  289. prefs[j] = prefs[j + 1];
  290. }
  291. nmx--;
  292. }
  293. }
  294. if (nmx == 0)
  295. {
  296. punt:
  297. if (seenlocal &&
  298.     (!TryNullMXList ||
  299.      (sm_gethostbyname(host, AF_INET) == NULL
  300. # if NETINET6
  301.       && sm_gethostbyname(host, AF_INET6) == NULL
  302. # endif /* NETINET6 */
  303.       )))
  304. {
  305. /*
  306. **  If we have deleted all MX entries, this is
  307. **  an error -- we should NEVER send to a host that
  308. **  has an MX, and this should have been caught
  309. **  earlier in the config file.
  310. **
  311. **  Some sites prefer to go ahead and try the
  312. **  A record anyway; that case is handled by
  313. **  setting TryNullMXList.  I believe this is a
  314. **  bad idea, but it's up to you....
  315. */
  316. *rcode = EX_CONFIG;
  317. syserr("MX list for %s points back to %s",
  318. host, MyHostName);
  319. return -1;
  320. }
  321. if (strlen(host) >= (SIZE_T) sizeof MXHostBuf)
  322. {
  323. *rcode = EX_CONFIG;
  324. syserr("Host name %s too long",
  325.        shortenstring(host, MAXSHORTSTR));
  326. return -1;
  327. }
  328. snprintf(MXHostBuf, sizeof MXHostBuf, "%s", host);
  329. mxhosts[0] = MXHostBuf;
  330. prefs[0] = 0;
  331. if (host[0] == '[')
  332. {
  333. register char *p;
  334. # if NETINET6
  335. struct sockaddr_in6 tmp6;
  336. # endif /* NETINET6 */
  337. /* this may be an MX suppression-style address */
  338. p = strchr(MXHostBuf, ']');
  339. if (p != NULL)
  340. {
  341. *p = '';
  342. if (inet_addr(&MXHostBuf[1]) != INADDR_NONE)
  343. {
  344. nmx++;
  345. *p = ']';
  346. }
  347. # if NETINET6
  348. else if (inet_pton(AF_INET6, &MXHostBuf[1],
  349.    &tmp6.sin6_addr) == 1)
  350. {
  351. nmx++;
  352. *p = ']';
  353. }
  354. # endif /* NETINET6 */
  355. else
  356. {
  357. trycanon = TRUE;
  358. mxhosts[0]++;
  359. }
  360. }
  361. }
  362. if (trycanon &&
  363.     getcanonname(mxhosts[0], sizeof MXHostBuf - 2, FALSE))
  364. {
  365. bp = &MXHostBuf[strlen(MXHostBuf)];
  366. if (bp[-1] != '.')
  367. {
  368. *bp++ = '.';
  369. *bp = '';
  370. }
  371. nmx = 1;
  372. }
  373. }
  374. /* if we have a default lowest preference, include that */
  375. if (fallbackMX != NULL && !seenlocal)
  376. {
  377. if (nmx > 0)
  378. prefs[nmx] = prefs[nmx - 1] + 1;
  379. else
  380. prefs[nmx] = 0;
  381. mxhosts[nmx++] = fallbackMX;
  382. }
  383. return nmx;
  384. }
  385. /*
  386. **  MXRAND -- create a randomizer for equal MX preferences
  387. **
  388. ** If two MX hosts have equal preferences we want to randomize
  389. ** the selection.  But in order for signatures to be the same,
  390. ** we need to randomize the same way each time.  This function
  391. ** computes a pseudo-random hash function from the host name.
  392. **
  393. ** Parameters:
  394. ** host -- the name of the host.
  395. **
  396. ** Returns:
  397. ** A random but repeatable value based on the host name.
  398. **
  399. ** Side Effects:
  400. ** none.
  401. */
  402. static int
  403. mxrand(host)
  404. register char *host;
  405. {
  406. int hfunc;
  407. static unsigned int seed;
  408. if (seed == 0)
  409. {
  410. seed = (int) curtime() & 0xffff;
  411. if (seed == 0)
  412. seed++;
  413. }
  414. if (tTd(17, 9))
  415. dprintf("mxrand(%s)", host);
  416. hfunc = seed;
  417. while (*host != '')
  418. {
  419. int c = *host++;
  420. if (isascii(c) && isupper(c))
  421. c = tolower(c);
  422. hfunc = ((hfunc << 1) ^ c) % 2003;
  423. }
  424. hfunc &= 0xff;
  425. hfunc++;
  426. if (tTd(17, 9))
  427. dprintf(" = %dn", hfunc);
  428. return hfunc;
  429. }
  430. /*
  431. **  BESTMX -- find the best MX for a name
  432. **
  433. ** This is really a hack, but I don't see any obvious way
  434. ** to generalize it at the moment.
  435. */
  436. /* ARGSUSED3 */
  437. char *
  438. bestmx_map_lookup(map, name, av, statp)
  439. MAP *map;
  440. char *name;
  441. char **av;
  442. int *statp;
  443. {
  444. int nmx;
  445. int saveopts = _res.options;
  446. int i, len = 0;
  447. char *p;
  448. char *mxhosts[MAXMXHOSTS + 1];
  449. char buf[PSBUFSIZE / 2];
  450. _res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
  451. nmx = getmxrr(name, mxhosts, NULL, FALSE, statp);
  452. _res.options = saveopts;
  453. if (nmx <= 0)
  454. return NULL;
  455. if (bitset(MF_MATCHONLY, map->map_mflags))
  456. return map_rewrite(map, name, strlen(name), NULL);
  457. if ((map->map_coldelim == '') || (nmx == 1))
  458. return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
  459. /*
  460. **  We were given a -z flag (return all MXs) and there are multiple
  461. **  ones.  We need to build them all into a list.
  462. */
  463. p = buf;
  464. for (i = 0; i < nmx; i++)
  465. {
  466. int slen;
  467. if (strchr(mxhosts[i], map->map_coldelim) != NULL)
  468. {
  469. syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
  470.        mxhosts[i], map->map_coldelim);
  471. return NULL;
  472. }
  473. slen = strlen(mxhosts[i]);
  474. if (len + slen + 2 > sizeof buf)
  475. break;
  476. if (i > 0)
  477. {
  478. *p++ = map->map_coldelim;
  479. len++;
  480. }
  481. (void) strlcpy(p, mxhosts[i], sizeof buf - len);
  482. p += slen;
  483. len += slen;
  484. }
  485. return map_rewrite(map, buf, len, av);
  486. }
  487. /*
  488. **  DNS_GETCANONNAME -- get the canonical name for named host using DNS
  489. **
  490. ** This algorithm tries to be smart about wildcard MX records.
  491. ** This is hard to do because DNS doesn't tell is if we matched
  492. ** against a wildcard or a specific MX.
  493. **
  494. ** We always prefer A & CNAME records, since these are presumed
  495. ** to be specific.
  496. **
  497. ** If we match an MX in one pass and lose it in the next, we use
  498. ** the old one.  For example, consider an MX matching *.FOO.BAR.COM.
  499. ** A hostname bletch.foo.bar.com will match against this MX, but
  500. ** will stop matching when we try bletch.bar.com -- so we know
  501. ** that bletch.foo.bar.com must have been right.  This fails if
  502. ** there was also an MX record matching *.BAR.COM, but there are
  503. ** some things that just can't be fixed.
  504. **
  505. ** Parameters:
  506. ** host -- a buffer containing the name of the host.
  507. ** This is a value-result parameter.
  508. ** hbsize -- the size of the host buffer.
  509. ** trymx -- if set, try MX records as well as A and CNAME.
  510. ** statp -- pointer to place to store status.
  511. **
  512. ** Returns:
  513. ** TRUE -- if the host matched.
  514. ** FALSE -- otherwise.
  515. */
  516. bool
  517. dns_getcanonname(host, hbsize, trymx, statp)
  518. char *host;
  519. int hbsize;
  520. bool trymx;
  521. int *statp;
  522. {
  523. register u_char *eom, *ap;
  524. register char *cp;
  525. register int n;
  526. HEADER *hp;
  527. querybuf answer;
  528. int ancount, qdcount;
  529. int ret;
  530. char **domain;
  531. int type;
  532. char **dp;
  533. char *mxmatch;
  534. bool amatch;
  535. bool gotmx = FALSE;
  536. int qtype;
  537. int loopcnt;
  538. char *xp;
  539. char nbuf[MAX(MAXPACKET, MAXDNAME*2+2)];
  540. char *searchlist[MAXDNSRCH+2];
  541. if (tTd(8, 2))
  542. dprintf("dns_getcanonname(%s, trymx=%d)n", host, trymx);
  543. if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  544. {
  545. *statp = EX_UNAVAILABLE;
  546. return FALSE;
  547. }
  548. /*
  549. **  Initialize domain search list.  If there is at least one
  550. **  dot in the name, search the unmodified name first so we
  551. **  find "vse.CS" in Czechoslovakia instead of in the local
  552. **  domain (e.g., vse.CS.Berkeley.EDU).  Note that there is no
  553. **  longer a country named Czechoslovakia but this type of problem
  554. **  is still present.
  555. **
  556. **  Older versions of the resolver could create this
  557. **  list by tearing apart the host name.
  558. */
  559. loopcnt = 0;
  560. cnameloop:
  561. /* Check for dots in the name */
  562. for (cp = host, n = 0; *cp != ''; cp++)
  563. if (*cp == '.')
  564. n++;
  565. /*
  566. **  If this is a simple name, determine whether it matches an
  567. **  alias in the file defined by the environment variable HOSTALIASES.
  568. */
  569. if (n == 0 && (xp = gethostalias(host)) != NULL)
  570. {
  571. if (loopcnt++ > MAXCNAMEDEPTH)
  572. {
  573. syserr("loop in ${HOSTALIASES} file");
  574. }
  575. else
  576. {
  577. (void) strlcpy(host, xp, hbsize);
  578. goto cnameloop;
  579. }
  580. }
  581. /*
  582. **  Build the search list.
  583. ** If there is at least one dot in name, start with a null
  584. ** domain to search the unmodified name first.
  585. ** If name does not end with a dot and search up local domain
  586. ** tree desired, append each local domain component to the
  587. ** search list; if name contains no dots and default domain
  588. ** name is desired, append default domain name to search list;
  589. ** else if name ends in a dot, remove that dot.
  590. */
  591. dp = searchlist;
  592. if (n > 0)
  593. *dp++ = "";
  594. if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options))
  595. {
  596. /* make sure there are less than MAXDNSRCH domains */
  597. for (domain = RES_DNSRCH_VARIABLE, ret = 0;
  598.      *domain != NULL && ret < MAXDNSRCH;
  599.      ret++)
  600. *dp++ = *domain++;
  601. }
  602. else if (n == 0 && bitset(RES_DEFNAMES, _res.options))
  603. {
  604. *dp++ = _res.defdname;
  605. }
  606. else if (*cp == '.')
  607. {
  608. *cp = '';
  609. }
  610. *dp = NULL;
  611. /*
  612. **  Now loop through the search list, appending each domain in turn
  613. **  name and searching for a match.
  614. */
  615. mxmatch = NULL;
  616. qtype = T_ANY;
  617. for (dp = searchlist; *dp != NULL; )
  618. {
  619. if (qtype == T_ANY)
  620. gotmx = FALSE;
  621. if (tTd(8, 5))
  622. dprintf("dns_getcanonname: trying %s.%s (%s)n",
  623. host, *dp,
  624. qtype == T_ANY ? "ANY" :
  625. # if NETINET6
  626. qtype == T_AAAA ? "AAAA" :
  627. # endif /* NETINET6 */
  628. qtype == T_A ? "A" :
  629. qtype == T_MX ? "MX" :
  630. "???");
  631. ret = res_querydomain(host, *dp, C_IN, qtype,
  632.       answer.qb2, sizeof(answer.qb2));
  633. if (ret <= 0)
  634. {
  635. if (tTd(8, 7))
  636. dprintf("tNO: errno=%d, h_errno=%dn",
  637. errno, h_errno);
  638. if (errno == ECONNREFUSED || h_errno == TRY_AGAIN)
  639. {
  640. /* the name server seems to be down */
  641. h_errno = TRY_AGAIN;
  642. *statp = EX_TEMPFAIL;
  643. return FALSE;
  644. }
  645. if (h_errno != HOST_NOT_FOUND)
  646. {
  647. /* might have another type of interest */
  648. if (qtype == T_ANY)
  649. {
  650. # if NETINET6
  651. qtype = T_AAAA;
  652. # else /* NETINET6 */
  653. qtype = T_A;
  654. # endif /* NETINET6 */
  655. continue;
  656. }
  657. # if NETINET6
  658. else if (qtype == T_AAAA)
  659. {
  660. qtype = T_A;
  661. continue;
  662. }
  663. # endif /* NETINET6 */
  664. else if (qtype == T_A && !gotmx &&
  665.  (trymx || **dp == ''))
  666. {
  667. qtype = T_MX;
  668. continue;
  669. }
  670. }
  671. /* definite no -- try the next domain */
  672. dp++;
  673. qtype = T_ANY;
  674. continue;
  675. }
  676. else if (tTd(8, 7))
  677. dprintf("tYESn");
  678. /* avoid problems after truncation in tcp packets */
  679. if (ret > sizeof(answer))
  680. ret = sizeof(answer);
  681. /*
  682. **  Appear to have a match.  Confirm it by searching for A or
  683. **  CNAME records.  If we don't have a local domain
  684. **  wild card MX record, we will accept MX as well.
  685. */
  686. hp = (HEADER *) &answer;
  687. ap = (u_char *) &answer + HFIXEDSZ;
  688. eom = (u_char *) &answer + ret;
  689. /* skip question part of response -- we know what we asked */
  690. for (qdcount = ntohs(hp->qdcount); qdcount--; ap += ret + QFIXEDSZ)
  691. {
  692. if ((ret = dn_skipname(ap, eom)) < 0)
  693. {
  694. if (tTd(8, 20))
  695. dprintf("qdcount failure (%d)n",
  696. ntohs(hp->qdcount));
  697. *statp = EX_SOFTWARE;
  698. return FALSE; /* ???XXX??? */
  699. }
  700. }
  701. amatch = FALSE;
  702. for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom;
  703. ap += n)
  704. {
  705. n = dn_expand((u_char *) &answer, eom, ap,
  706.       (RES_UNC_T) nbuf, sizeof nbuf);
  707. if (n < 0)
  708. break;
  709. ap += n;
  710. GETSHORT(type, ap);
  711. ap += INT16SZ + INT32SZ;
  712. GETSHORT(n, ap);
  713. switch (type)
  714. {
  715.   case T_MX:
  716. gotmx = TRUE;
  717. if (**dp != '' && HasWildcardMX)
  718. {
  719. /*
  720. **  If we are using MX matches and have
  721. **  not yet gotten one, save this one
  722. **  but keep searching for an A or
  723. **  CNAME match.
  724. */
  725. if (trymx && mxmatch == NULL)
  726. mxmatch = *dp;
  727. continue;
  728. }
  729. /*
  730. **  If we did not append a domain name, this
  731. **  must have been a canonical name to start
  732. **  with.  Even if we did append a domain name,
  733. **  in the absence of a wildcard MX this must
  734. **  still be a real MX match.
  735. **  Such MX matches are as good as an A match,
  736. **  fall through.
  737. */
  738. /* FALLTHROUGH */
  739. # if NETINET6
  740.   case T_AAAA:
  741. /* Flag that a good match was found */
  742. amatch = TRUE;
  743. /* continue in case a CNAME also exists */
  744. continue;
  745. # endif /* NETINET6 */
  746.   case T_A:
  747. /* Flag that a good match was found */
  748. amatch = TRUE;
  749. /* continue in case a CNAME also exists */
  750. continue;
  751.   case T_CNAME:
  752. if (DontExpandCnames)
  753. {
  754. /* got CNAME -- guaranteed canonical */
  755. amatch = TRUE;
  756. break;
  757. }
  758. if (loopcnt++ > MAXCNAMEDEPTH)
  759. {
  760. /*XXX should notify postmaster XXX*/
  761. message("DNS failure: CNAME loop for %s",
  762. host);
  763. if (CurEnv->e_message == NULL)
  764. {
  765. char ebuf[MAXLINE];
  766. snprintf(ebuf, sizeof ebuf,
  767. "Deferred: DNS failure: CNAME loop for %.100s",
  768. host);
  769. CurEnv->e_message = newstr(ebuf);
  770. }
  771. h_errno = NO_RECOVERY;
  772. *statp = EX_CONFIG;
  773. return FALSE;
  774. }
  775. /* value points at name */
  776. if ((ret = dn_expand((u_char *)&answer,
  777.     eom, ap, (RES_UNC_T) nbuf, sizeof(nbuf))) < 0)
  778. break;
  779. (void)strlcpy(host, nbuf, hbsize);
  780. /*
  781. **  RFC 1034 section 3.6 specifies that CNAME
  782. **  should point at the canonical name -- but
  783. **  urges software to try again anyway.
  784. */
  785. goto cnameloop;
  786.   default:
  787. /* not a record of interest */
  788. continue;
  789. }
  790. }
  791. if (amatch)
  792. {
  793. /*
  794. **  Got a good match -- either an A, CNAME, or an
  795. **  exact MX record.  Save it and get out of here.
  796. */
  797. mxmatch = *dp;
  798. break;
  799. }
  800. /*
  801. **  Nothing definitive yet.
  802. ** If this was a T_ANY query, we don't really know what
  803. ** was returned -- it might have been a T_NS,
  804. ** for example.  Try T_A to be more specific
  805. ** during the next pass.
  806. ** If this was a T_A query and we haven't yet found a MX
  807. ** match, try T_MX if allowed to do so.
  808. ** Otherwise, try the next domain.
  809. */
  810. if (qtype == T_ANY)
  811. {
  812. # if NETINET6
  813. qtype = T_AAAA;
  814. # else /* NETINET6 */
  815. qtype = T_A;
  816. # endif /* NETINET6 */
  817. }
  818. # if NETINET6
  819. else if (qtype == T_AAAA)
  820. qtype = T_A;
  821. # endif /* NETINET6 */
  822. else if (qtype == T_A && !gotmx && (trymx || **dp == ''))
  823. qtype = T_MX;
  824. else
  825. {
  826. qtype = T_ANY;
  827. dp++;
  828. }
  829. }
  830. /* if nothing was found, we are done */
  831. if (mxmatch == NULL)
  832. {
  833. *statp = EX_NOHOST;
  834. return FALSE;
  835. }
  836. /*
  837. **  Create canonical name and return.
  838. **  If saved domain name is null, name was already canonical.
  839. **  Otherwise append the saved domain name.
  840. */
  841. (void) snprintf(nbuf, sizeof nbuf, "%.*s%s%.*s", MAXDNAME, host,
  842. *mxmatch == '' ? "" : ".",
  843. MAXDNAME, mxmatch);
  844. (void) strlcpy(host, nbuf, hbsize);
  845. if (tTd(8, 5))
  846. dprintf("dns_getcanonname: %sn", host);
  847. *statp = EX_OK;
  848. return TRUE;
  849. }
  850. static char *
  851. gethostalias(host)
  852. char *host;
  853. {
  854. char *fname;
  855. FILE *fp;
  856. register char *p = NULL;
  857. long sff = SFF_REGONLY;
  858. char buf[MAXLINE];
  859. static char hbuf[MAXDNAME];
  860. if (DontLockReadFiles)
  861. sff |= SFF_NOLOCK;
  862. fname = getenv("HOSTALIASES");
  863. if (fname == NULL ||
  864.     (fp = safefopen(fname, O_RDONLY, 0, sff)) == NULL)
  865. return NULL;
  866. while (fgets(buf, sizeof buf, fp) != NULL)
  867. {
  868. for (p = buf; p != '' && !(isascii(*p) && isspace(*p)); p++)
  869. continue;
  870. if (*p == 0)
  871. {
  872. /* syntax error */
  873. continue;
  874. }
  875. *p++ = '';
  876. if (strcasecmp(buf, host) == 0)
  877. break;
  878. }
  879. if (feof(fp))
  880. {
  881. /* no match */
  882. (void) fclose(fp);
  883. return NULL;
  884. }
  885. (void) fclose(fp);
  886. /* got a match; extract the equivalent name */
  887. while (*p != '' && isascii(*p) && isspace(*p))
  888. p++;
  889. host = p;
  890. while (*p != '' && !(isascii(*p) && isspace(*p)))
  891. p++;
  892. *p = '';
  893. (void) strlcpy(hbuf, host, sizeof hbuf);
  894. return hbuf;
  895. }
  896. #endif /* NAMED_BIND */