1c2aa98e2SPeter Wemm /* 2d9986b26SGregory Neil Shapiro * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1986, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 1406f25ae9SGregory Neil Shapiro #include <sendmail.h> 15c2aa98e2SPeter Wemm 16c2aa98e2SPeter Wemm #if NAMED_BIND 17a7ec597cSGregory Neil Shapiro SM_RCSID("@(#)$Id: domain.c,v 8.181.2.9 2003/08/11 23:23:40 gshapiro Exp $ (with name server)") 1806f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */ 19a7ec597cSGregory Neil Shapiro SM_RCSID("@(#)$Id: domain.c,v 8.181.2.9 2003/08/11 23:23:40 gshapiro Exp $ (without name server)") 2006f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 21c2aa98e2SPeter Wemm 22c2aa98e2SPeter Wemm #if NAMED_BIND 23c2aa98e2SPeter Wemm 24c2aa98e2SPeter Wemm # include <arpa/inet.h> 25c2aa98e2SPeter Wemm 2640266059SGregory Neil Shapiro 27c2aa98e2SPeter Wemm /* 28c2aa98e2SPeter Wemm ** The standard udp packet size PACKETSZ (512) is not sufficient for some 29c2aa98e2SPeter Wemm ** nameserver answers containing very many resource records. The resolver 30c2aa98e2SPeter Wemm ** may switch to tcp and retry if it detects udp packet overflow. 31c2aa98e2SPeter Wemm ** Also note that the resolver routines res_query and res_search return 32c2aa98e2SPeter Wemm ** the size of the *un*truncated answer in case the supplied answer buffer 33c2aa98e2SPeter Wemm ** it not big enough to accommodate the entire answer. 34c2aa98e2SPeter Wemm */ 35c2aa98e2SPeter Wemm 36c2aa98e2SPeter Wemm # ifndef MAXPACKET 37c2aa98e2SPeter Wemm # define MAXPACKET 8192 /* max packet size used internally by BIND */ 3806f25ae9SGregory Neil Shapiro # endif /* ! MAXPACKET */ 39c2aa98e2SPeter Wemm 40c2aa98e2SPeter Wemm typedef union 41c2aa98e2SPeter Wemm { 42c2aa98e2SPeter Wemm HEADER qb1; 4340266059SGregory Neil Shapiro unsigned char qb2[MAXPACKET]; 44c2aa98e2SPeter Wemm } querybuf; 45c2aa98e2SPeter Wemm 46c2aa98e2SPeter Wemm # ifndef MXHOSTBUFSIZE 47c2aa98e2SPeter Wemm # define MXHOSTBUFSIZE (128 * MAXMXHOSTS) 4806f25ae9SGregory Neil Shapiro # endif /* ! MXHOSTBUFSIZE */ 49c2aa98e2SPeter Wemm 50c2aa98e2SPeter Wemm static char MXHostBuf[MXHOSTBUFSIZE]; 5140266059SGregory Neil Shapiro #if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2) 5240266059SGregory Neil Shapiro ERROR: _MXHOSTBUFSIZE is out of range 5340266059SGregory Neil Shapiro #endif /* (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2) */ 54c2aa98e2SPeter Wemm 55c2aa98e2SPeter Wemm # ifndef MAXDNSRCH 56c2aa98e2SPeter Wemm # define MAXDNSRCH 6 /* number of possible domains to search */ 5706f25ae9SGregory Neil Shapiro # endif /* ! MAXDNSRCH */ 5806f25ae9SGregory Neil Shapiro 5906f25ae9SGregory Neil Shapiro # ifndef RES_DNSRCH_VARIABLE 6006f25ae9SGregory Neil Shapiro # define RES_DNSRCH_VARIABLE _res.dnsrch 6106f25ae9SGregory Neil Shapiro # endif /* ! RES_DNSRCH_VARIABLE */ 62c2aa98e2SPeter Wemm 63c2aa98e2SPeter Wemm # ifndef NO_DATA 64c2aa98e2SPeter Wemm # define NO_DATA NO_ADDRESS 6506f25ae9SGregory Neil Shapiro # endif /* ! NO_DATA */ 66c2aa98e2SPeter Wemm 67c2aa98e2SPeter Wemm # ifndef HFIXEDSZ 68c2aa98e2SPeter Wemm # define HFIXEDSZ 12 /* sizeof(HEADER) */ 6906f25ae9SGregory Neil Shapiro # endif /* ! HFIXEDSZ */ 70c2aa98e2SPeter Wemm 71c2aa98e2SPeter Wemm # define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */ 72c2aa98e2SPeter Wemm 73c2aa98e2SPeter Wemm # if defined(__RES) && (__RES >= 19940415) 74c2aa98e2SPeter Wemm # define RES_UNC_T char * 7506f25ae9SGregory Neil Shapiro # else /* defined(__RES) && (__RES >= 19940415) */ 7640266059SGregory Neil Shapiro # define RES_UNC_T unsigned char * 7706f25ae9SGregory Neil Shapiro # endif /* defined(__RES) && (__RES >= 19940415) */ 7806f25ae9SGregory Neil Shapiro 7906f25ae9SGregory Neil Shapiro static char *gethostalias __P((char *)); 8006f25ae9SGregory Neil Shapiro static int mxrand __P((char *)); 8140266059SGregory Neil Shapiro static int fallbackmxrr __P((int, unsigned short *, char **)); 8206f25ae9SGregory Neil Shapiro 8340266059SGregory Neil Shapiro /* 8440266059SGregory Neil Shapiro ** GETFALLBACKMXRR -- get MX resource records for fallback MX host. 8540266059SGregory Neil Shapiro ** 8640266059SGregory Neil Shapiro ** We have to initialize this once before doing anything else. 8740266059SGregory Neil Shapiro ** Moreover, we have to repeat this from time to time to avoid 8840266059SGregory Neil Shapiro ** stale data, e.g., in persistent queue runners. 8940266059SGregory Neil Shapiro ** This should be done in a parent process so the child 9040266059SGregory Neil Shapiro ** processes have the right data. 9140266059SGregory Neil Shapiro ** 9240266059SGregory Neil Shapiro ** Parameters: 9340266059SGregory Neil Shapiro ** host -- the name of the fallback MX host. 9440266059SGregory Neil Shapiro ** 9540266059SGregory Neil Shapiro ** Returns: 9640266059SGregory Neil Shapiro ** number of MX records. 9740266059SGregory Neil Shapiro ** 9840266059SGregory Neil Shapiro ** Side Effects: 9940266059SGregory Neil Shapiro ** Populates NumFallBackMXHosts and fbhosts. 10040266059SGregory Neil Shapiro ** Sets renewal time (based on TTL). 10140266059SGregory Neil Shapiro */ 10240266059SGregory Neil Shapiro 10340266059SGregory Neil Shapiro int NumFallBackMXHosts = 0; /* Number of fallback MX hosts (after MX expansion) */ 10440266059SGregory Neil Shapiro static char *fbhosts[MAXMXHOSTS + 1]; 10540266059SGregory Neil Shapiro 10640266059SGregory Neil Shapiro int 10740266059SGregory Neil Shapiro getfallbackmxrr(host) 10840266059SGregory Neil Shapiro char *host; 10940266059SGregory Neil Shapiro { 11040266059SGregory Neil Shapiro int i, rcode; 11140266059SGregory Neil Shapiro int ttl; 11240266059SGregory Neil Shapiro static time_t renew = 0; 11340266059SGregory Neil Shapiro 11440266059SGregory Neil Shapiro #if 0 11540266059SGregory Neil Shapiro /* This is currently done before this function is called. */ 11640266059SGregory Neil Shapiro if (host == NULL || *host == '\0') 11740266059SGregory Neil Shapiro return 0; 11840266059SGregory Neil Shapiro #endif /* 0 */ 11940266059SGregory Neil Shapiro if (NumFallBackMXHosts > 0 && renew > curtime()) 12040266059SGregory Neil Shapiro return NumFallBackMXHosts; 12140266059SGregory Neil Shapiro if (host[0] == '[') 12240266059SGregory Neil Shapiro { 12340266059SGregory Neil Shapiro fbhosts[0] = host; 12440266059SGregory Neil Shapiro NumFallBackMXHosts = 1; 12540266059SGregory Neil Shapiro } 12640266059SGregory Neil Shapiro else 12740266059SGregory Neil Shapiro { 12840266059SGregory Neil Shapiro /* free old data */ 12940266059SGregory Neil Shapiro for (i = 0; i < NumFallBackMXHosts; i++) 13040266059SGregory Neil Shapiro sm_free(fbhosts[i]); 13140266059SGregory Neil Shapiro 13240266059SGregory Neil Shapiro /* get new data */ 13340266059SGregory Neil Shapiro NumFallBackMXHosts = getmxrr(host, fbhosts, NULL, false, 13440266059SGregory Neil Shapiro &rcode, false, &ttl); 13540266059SGregory Neil Shapiro renew = curtime() + ttl; 13640266059SGregory Neil Shapiro for (i = 0; i < NumFallBackMXHosts; i++) 13740266059SGregory Neil Shapiro fbhosts[i] = newstr(fbhosts[i]); 13840266059SGregory Neil Shapiro } 13940266059SGregory Neil Shapiro return NumFallBackMXHosts; 14040266059SGregory Neil Shapiro } 14140266059SGregory Neil Shapiro 14240266059SGregory Neil Shapiro /* 14340266059SGregory Neil Shapiro ** FALLBACKMXRR -- add MX resource records for fallback MX host to list. 14440266059SGregory Neil Shapiro ** 14540266059SGregory Neil Shapiro ** Parameters: 14640266059SGregory Neil Shapiro ** nmx -- current number of MX records. 14740266059SGregory Neil Shapiro ** prefs -- array of preferences. 14840266059SGregory Neil Shapiro ** mxhosts -- array of MX hosts (maximum size: MAXMXHOSTS) 14940266059SGregory Neil Shapiro ** 15040266059SGregory Neil Shapiro ** Returns: 15140266059SGregory Neil Shapiro ** new number of MX records. 15240266059SGregory Neil Shapiro ** 15340266059SGregory Neil Shapiro ** Side Effects: 15440266059SGregory Neil Shapiro ** If FallBackMX was set, it appends the MX records for 15540266059SGregory Neil Shapiro ** that host to mxhosts (and modifies prefs accordingly). 15640266059SGregory Neil Shapiro */ 15740266059SGregory Neil Shapiro 15840266059SGregory Neil Shapiro static int 15940266059SGregory Neil Shapiro fallbackmxrr(nmx, prefs, mxhosts) 16040266059SGregory Neil Shapiro int nmx; 16140266059SGregory Neil Shapiro unsigned short *prefs; 16240266059SGregory Neil Shapiro char **mxhosts; 16340266059SGregory Neil Shapiro { 16440266059SGregory Neil Shapiro int i; 16540266059SGregory Neil Shapiro 16640266059SGregory Neil Shapiro for (i = 0; i < NumFallBackMXHosts && nmx < MAXMXHOSTS; i++) 16740266059SGregory Neil Shapiro { 16840266059SGregory Neil Shapiro if (nmx > 0) 16940266059SGregory Neil Shapiro prefs[nmx] = prefs[nmx - 1] + 1; 17040266059SGregory Neil Shapiro else 17140266059SGregory Neil Shapiro prefs[nmx] = 0; 17240266059SGregory Neil Shapiro mxhosts[nmx++] = fbhosts[i]; 17340266059SGregory Neil Shapiro } 17440266059SGregory Neil Shapiro return nmx; 17540266059SGregory Neil Shapiro } 17640266059SGregory Neil Shapiro 17740266059SGregory Neil Shapiro /* 178c2aa98e2SPeter Wemm ** GETMXRR -- get MX resource records for a domain 179c2aa98e2SPeter Wemm ** 180c2aa98e2SPeter Wemm ** Parameters: 181c2aa98e2SPeter Wemm ** host -- the name of the host to MX. 182c2aa98e2SPeter Wemm ** mxhosts -- a pointer to a return buffer of MX records. 18306f25ae9SGregory Neil Shapiro ** mxprefs -- a pointer to a return buffer of MX preferences. 18406f25ae9SGregory Neil Shapiro ** If NULL, don't try to populate. 18540266059SGregory Neil Shapiro ** droplocalhost -- If true, all MX records less preferred 186c2aa98e2SPeter Wemm ** than the local host (as determined by $=w) will 187c2aa98e2SPeter Wemm ** be discarded. 188c2aa98e2SPeter Wemm ** rcode -- a pointer to an EX_ status code. 18940266059SGregory Neil Shapiro ** tryfallback -- add also fallback MX host? 19040266059SGregory Neil Shapiro ** pttl -- pointer to return TTL (can be NULL). 191c2aa98e2SPeter Wemm ** 192c2aa98e2SPeter Wemm ** Returns: 193c2aa98e2SPeter Wemm ** The number of MX records found. 194c2aa98e2SPeter Wemm ** -1 if there is an internal failure. 195c2aa98e2SPeter Wemm ** If no MX records are found, mxhosts[0] is set to host 196c2aa98e2SPeter Wemm ** and 1 is returned. 19740266059SGregory Neil Shapiro ** 19840266059SGregory Neil Shapiro ** Side Effects: 19940266059SGregory Neil Shapiro ** The entries made for mxhosts point to a static array 20040266059SGregory Neil Shapiro ** MXHostBuf[MXHOSTBUFSIZE], so the data needs to be copied, 20140266059SGregory Neil Shapiro ** if it must be preserved across calls to this function. 202c2aa98e2SPeter Wemm */ 203c2aa98e2SPeter Wemm 204c2aa98e2SPeter Wemm int 20540266059SGregory Neil Shapiro getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl) 206c2aa98e2SPeter Wemm char *host; 207c2aa98e2SPeter Wemm char **mxhosts; 20840266059SGregory Neil Shapiro unsigned short *mxprefs; 209c2aa98e2SPeter Wemm bool droplocalhost; 210c2aa98e2SPeter Wemm int *rcode; 21140266059SGregory Neil Shapiro bool tryfallback; 21240266059SGregory Neil Shapiro int *pttl; 213c2aa98e2SPeter Wemm { 21440266059SGregory Neil Shapiro register unsigned char *eom, *cp; 215c2aa98e2SPeter Wemm register int i, j, n; 216c2aa98e2SPeter Wemm int nmx = 0; 217c2aa98e2SPeter Wemm register char *bp; 218c2aa98e2SPeter Wemm HEADER *hp; 219c2aa98e2SPeter Wemm querybuf answer; 220c2aa98e2SPeter Wemm int ancount, qdcount, buflen; 22140266059SGregory Neil Shapiro bool seenlocal = false; 22240266059SGregory Neil Shapiro unsigned short pref, type; 22340266059SGregory Neil Shapiro unsigned short localpref = 256; 224c2aa98e2SPeter Wemm char *fallbackMX = FallBackMX; 22540266059SGregory Neil Shapiro bool trycanon = false; 22640266059SGregory Neil Shapiro unsigned short *prefs; 227c2aa98e2SPeter Wemm int (*resfunc)(); 22840266059SGregory Neil Shapiro unsigned short prefer[MAXMXHOSTS]; 229c2aa98e2SPeter Wemm int weight[MAXMXHOSTS]; 23040266059SGregory Neil Shapiro int ttl = 0; 23106f25ae9SGregory Neil Shapiro extern int res_query(), res_search(); 232c2aa98e2SPeter Wemm 233c2aa98e2SPeter Wemm if (tTd(8, 2)) 23440266059SGregory Neil Shapiro sm_dprintf("getmxrr(%s, droplocalhost=%d)\n", 23506f25ae9SGregory Neil Shapiro host, droplocalhost); 236a7ec597cSGregory Neil Shapiro if (*host == '\0') 237a7ec597cSGregory Neil Shapiro return 0; 238c2aa98e2SPeter Wemm 23940266059SGregory Neil Shapiro if ((fallbackMX != NULL && droplocalhost && 24040266059SGregory Neil Shapiro wordinclass(fallbackMX, 'w')) || !tryfallback) 241c2aa98e2SPeter Wemm { 242c2aa98e2SPeter Wemm /* don't use fallback for this pass */ 243c2aa98e2SPeter Wemm fallbackMX = NULL; 244c2aa98e2SPeter Wemm } 245c2aa98e2SPeter Wemm 246c2aa98e2SPeter Wemm *rcode = EX_OK; 247c2aa98e2SPeter Wemm 24806f25ae9SGregory Neil Shapiro if (mxprefs != NULL) 24906f25ae9SGregory Neil Shapiro prefs = mxprefs; 25006f25ae9SGregory Neil Shapiro else 25106f25ae9SGregory Neil Shapiro prefs = prefer; 25206f25ae9SGregory Neil Shapiro 253c2aa98e2SPeter Wemm /* efficiency hack -- numeric or non-MX lookups */ 254c2aa98e2SPeter Wemm if (host[0] == '[') 255c2aa98e2SPeter Wemm goto punt; 256c2aa98e2SPeter Wemm 257c2aa98e2SPeter Wemm /* 258c2aa98e2SPeter Wemm ** If we don't have MX records in our host switch, don't 259c2aa98e2SPeter Wemm ** try for MX records. Note that this really isn't "right", 260c2aa98e2SPeter Wemm ** since we might be set up to try NIS first and then DNS; 261c2aa98e2SPeter Wemm ** if the host is found in NIS we really shouldn't be doing 262c2aa98e2SPeter Wemm ** MX lookups. However, that should be a degenerate case. 263c2aa98e2SPeter Wemm */ 264c2aa98e2SPeter Wemm 265c2aa98e2SPeter Wemm if (!UseNameServer) 266c2aa98e2SPeter Wemm goto punt; 267c2aa98e2SPeter Wemm if (HasWildcardMX && ConfigLevel >= 6) 268c2aa98e2SPeter Wemm resfunc = res_query; 269c2aa98e2SPeter Wemm else 270c2aa98e2SPeter Wemm resfunc = res_search; 271c2aa98e2SPeter Wemm 272c2aa98e2SPeter Wemm errno = 0; 27340266059SGregory Neil Shapiro n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer, 27440266059SGregory Neil Shapiro sizeof(answer)); 275c2aa98e2SPeter Wemm if (n < 0) 276c2aa98e2SPeter Wemm { 277c2aa98e2SPeter Wemm if (tTd(8, 1)) 27840266059SGregory Neil Shapiro sm_dprintf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n", 27940266059SGregory Neil Shapiro host == NULL ? "<NULL>" : host, errno, h_errno); 280c2aa98e2SPeter Wemm switch (h_errno) 281c2aa98e2SPeter Wemm { 282c2aa98e2SPeter Wemm case NO_DATA: 28340266059SGregory Neil Shapiro trycanon = true; 28406f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 285c2aa98e2SPeter Wemm 286c2aa98e2SPeter Wemm case NO_RECOVERY: 287c2aa98e2SPeter Wemm /* no MX data on this host */ 288c2aa98e2SPeter Wemm goto punt; 289c2aa98e2SPeter Wemm 290c2aa98e2SPeter Wemm case HOST_NOT_FOUND: 291c2aa98e2SPeter Wemm # if BROKEN_RES_SEARCH 292c2aa98e2SPeter Wemm case 0: /* Ultrix resolver retns failure w/ h_errno=0 */ 29306f25ae9SGregory Neil Shapiro # endif /* BROKEN_RES_SEARCH */ 294c2aa98e2SPeter Wemm /* host doesn't exist in DNS; might be in /etc/hosts */ 29540266059SGregory Neil Shapiro trycanon = true; 296c2aa98e2SPeter Wemm *rcode = EX_NOHOST; 297c2aa98e2SPeter Wemm goto punt; 298c2aa98e2SPeter Wemm 299c2aa98e2SPeter Wemm case TRY_AGAIN: 300c2aa98e2SPeter Wemm case -1: 301c2aa98e2SPeter Wemm /* couldn't connect to the name server */ 302c2aa98e2SPeter Wemm if (fallbackMX != NULL) 303c2aa98e2SPeter Wemm { 304c2aa98e2SPeter Wemm /* name server is hosed -- push to fallback */ 30540266059SGregory Neil Shapiro return fallbackmxrr(nmx, prefs, mxhosts); 306c2aa98e2SPeter Wemm } 307c2aa98e2SPeter Wemm /* it might come up later; better queue it up */ 308c2aa98e2SPeter Wemm *rcode = EX_TEMPFAIL; 309c2aa98e2SPeter Wemm break; 310c2aa98e2SPeter Wemm 311c2aa98e2SPeter Wemm default: 31240266059SGregory Neil Shapiro syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)", 313c2aa98e2SPeter Wemm host, h_errno); 314c2aa98e2SPeter Wemm *rcode = EX_OSERR; 315c2aa98e2SPeter Wemm break; 316c2aa98e2SPeter Wemm } 317c2aa98e2SPeter Wemm 318c2aa98e2SPeter Wemm /* irreconcilable differences */ 31906f25ae9SGregory Neil Shapiro return -1; 320c2aa98e2SPeter Wemm } 321c2aa98e2SPeter Wemm 322c2aa98e2SPeter Wemm /* avoid problems after truncation in tcp packets */ 323c2aa98e2SPeter Wemm if (n > sizeof(answer)) 324c2aa98e2SPeter Wemm n = sizeof(answer); 325c2aa98e2SPeter Wemm 326c2aa98e2SPeter Wemm /* find first satisfactory answer */ 327c2aa98e2SPeter Wemm hp = (HEADER *)&answer; 32840266059SGregory Neil Shapiro cp = (unsigned char *)&answer + HFIXEDSZ; 32940266059SGregory Neil Shapiro eom = (unsigned char *)&answer + n; 33040266059SGregory Neil Shapiro for (qdcount = ntohs((unsigned short) hp->qdcount); 33106f25ae9SGregory Neil Shapiro qdcount--; 33206f25ae9SGregory Neil Shapiro cp += n + QFIXEDSZ) 33306f25ae9SGregory Neil Shapiro { 334c2aa98e2SPeter Wemm if ((n = dn_skipname(cp, eom)) < 0) 335c2aa98e2SPeter Wemm goto punt; 33606f25ae9SGregory Neil Shapiro } 33740266059SGregory Neil Shapiro 33840266059SGregory Neil Shapiro /* NOTE: see definition of MXHostBuf! */ 339c2aa98e2SPeter Wemm buflen = sizeof(MXHostBuf) - 1; 34040266059SGregory Neil Shapiro SM_ASSERT(buflen > 0); 341c2aa98e2SPeter Wemm bp = MXHostBuf; 34240266059SGregory Neil Shapiro ancount = ntohs((unsigned short) hp->ancount); 34340266059SGregory Neil Shapiro 34440266059SGregory Neil Shapiro /* See RFC 1035 for layout of RRs. */ 34540266059SGregory Neil Shapiro /* XXX leave room for FallBackMX ? */ 346c2aa98e2SPeter Wemm while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1) 347c2aa98e2SPeter Wemm { 34840266059SGregory Neil Shapiro if ((n = dn_expand((unsigned char *)&answer, eom, cp, 34940266059SGregory Neil Shapiro (RES_UNC_T) bp, buflen)) < 0) 350c2aa98e2SPeter Wemm break; 351c2aa98e2SPeter Wemm cp += n; 352c2aa98e2SPeter Wemm GETSHORT(type, cp); 35340266059SGregory Neil Shapiro cp += INT16SZ; /* skip over class */ 35440266059SGregory Neil Shapiro GETLONG(ttl, cp); 35540266059SGregory Neil Shapiro GETSHORT(n, cp); /* rdlength */ 356c2aa98e2SPeter Wemm if (type != T_MX) 357c2aa98e2SPeter Wemm { 358c2aa98e2SPeter Wemm if (tTd(8, 8) || _res.options & RES_DEBUG) 35940266059SGregory Neil Shapiro sm_dprintf("unexpected answer type %d, size %d\n", 360c2aa98e2SPeter Wemm type, n); 361c2aa98e2SPeter Wemm cp += n; 362c2aa98e2SPeter Wemm continue; 363c2aa98e2SPeter Wemm } 364c2aa98e2SPeter Wemm GETSHORT(pref, cp); 36540266059SGregory Neil Shapiro if ((n = dn_expand((unsigned char *)&answer, eom, cp, 366c2aa98e2SPeter Wemm (RES_UNC_T) bp, buflen)) < 0) 367c2aa98e2SPeter Wemm break; 368c2aa98e2SPeter Wemm cp += n; 36940266059SGregory Neil Shapiro n = strlen(bp); 37040266059SGregory Neil Shapiro # if 0 37140266059SGregory Neil Shapiro /* Can this happen? */ 37240266059SGregory Neil Shapiro if (n == 0) 37340266059SGregory Neil Shapiro { 37440266059SGregory Neil Shapiro if (LogLevel > 4) 37540266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 37640266059SGregory Neil Shapiro "MX records for %s contain empty string", 37740266059SGregory Neil Shapiro host); 37840266059SGregory Neil Shapiro continue; 37940266059SGregory Neil Shapiro } 38040266059SGregory Neil Shapiro # endif /* 0 */ 381c2aa98e2SPeter Wemm if (wordinclass(bp, 'w')) 382c2aa98e2SPeter Wemm { 383c2aa98e2SPeter Wemm if (tTd(8, 3)) 38440266059SGregory Neil Shapiro sm_dprintf("found localhost (%s) in MX list, pref=%d\n", 385c2aa98e2SPeter Wemm bp, pref); 386c2aa98e2SPeter Wemm if (droplocalhost) 387c2aa98e2SPeter Wemm { 388c2aa98e2SPeter Wemm if (!seenlocal || pref < localpref) 389c2aa98e2SPeter Wemm localpref = pref; 39040266059SGregory Neil Shapiro seenlocal = true; 391c2aa98e2SPeter Wemm continue; 392c2aa98e2SPeter Wemm } 393c2aa98e2SPeter Wemm weight[nmx] = 0; 394c2aa98e2SPeter Wemm } 395c2aa98e2SPeter Wemm else 396c2aa98e2SPeter Wemm weight[nmx] = mxrand(bp); 39706f25ae9SGregory Neil Shapiro prefs[nmx] = pref; 398c2aa98e2SPeter Wemm mxhosts[nmx++] = bp; 399c2aa98e2SPeter Wemm bp += n; 400c2aa98e2SPeter Wemm if (bp[-1] != '.') 401c2aa98e2SPeter Wemm { 402c2aa98e2SPeter Wemm *bp++ = '.'; 403c2aa98e2SPeter Wemm n++; 404c2aa98e2SPeter Wemm } 405c2aa98e2SPeter Wemm *bp++ = '\0'; 40640266059SGregory Neil Shapiro if (buflen < n + 1) 40740266059SGregory Neil Shapiro { 40840266059SGregory Neil Shapiro /* don't want to wrap buflen */ 40940266059SGregory Neil Shapiro break; 41040266059SGregory Neil Shapiro } 411c2aa98e2SPeter Wemm buflen -= n + 1; 412c2aa98e2SPeter Wemm } 413c2aa98e2SPeter Wemm 41440266059SGregory Neil Shapiro /* return only one TTL entry, that should be sufficient */ 41540266059SGregory Neil Shapiro if (ttl > 0 && pttl != NULL) 41640266059SGregory Neil Shapiro *pttl = ttl; 41740266059SGregory Neil Shapiro 418c2aa98e2SPeter Wemm /* sort the records */ 419c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 420c2aa98e2SPeter Wemm { 421c2aa98e2SPeter Wemm for (j = i + 1; j < nmx; j++) 422c2aa98e2SPeter Wemm { 42306f25ae9SGregory Neil Shapiro if (prefs[i] > prefs[j] || 42406f25ae9SGregory Neil Shapiro (prefs[i] == prefs[j] && weight[i] > weight[j])) 425c2aa98e2SPeter Wemm { 426c2aa98e2SPeter Wemm register int temp; 427c2aa98e2SPeter Wemm register char *temp1; 428c2aa98e2SPeter Wemm 42906f25ae9SGregory Neil Shapiro temp = prefs[i]; 43006f25ae9SGregory Neil Shapiro prefs[i] = prefs[j]; 43106f25ae9SGregory Neil Shapiro prefs[j] = temp; 432c2aa98e2SPeter Wemm temp1 = mxhosts[i]; 433c2aa98e2SPeter Wemm mxhosts[i] = mxhosts[j]; 434c2aa98e2SPeter Wemm mxhosts[j] = temp1; 435c2aa98e2SPeter Wemm temp = weight[i]; 436c2aa98e2SPeter Wemm weight[i] = weight[j]; 437c2aa98e2SPeter Wemm weight[j] = temp; 438c2aa98e2SPeter Wemm } 439c2aa98e2SPeter Wemm } 44006f25ae9SGregory Neil Shapiro if (seenlocal && prefs[i] >= localpref) 441c2aa98e2SPeter Wemm { 442c2aa98e2SPeter Wemm /* truncate higher preference part of list */ 443c2aa98e2SPeter Wemm nmx = i; 444c2aa98e2SPeter Wemm } 445c2aa98e2SPeter Wemm } 446c2aa98e2SPeter Wemm 447c2aa98e2SPeter Wemm /* delete duplicates from list (yes, some bozos have duplicates) */ 448c2aa98e2SPeter Wemm for (i = 0; i < nmx - 1; ) 449c2aa98e2SPeter Wemm { 45040266059SGregory Neil Shapiro if (sm_strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0) 451c2aa98e2SPeter Wemm i++; 452c2aa98e2SPeter Wemm else 453c2aa98e2SPeter Wemm { 454c2aa98e2SPeter Wemm /* compress out duplicate */ 455c2aa98e2SPeter Wemm for (j = i + 1; j < nmx; j++) 45606f25ae9SGregory Neil Shapiro { 457c2aa98e2SPeter Wemm mxhosts[j] = mxhosts[j + 1]; 45806f25ae9SGregory Neil Shapiro prefs[j] = prefs[j + 1]; 45906f25ae9SGregory Neil Shapiro } 460c2aa98e2SPeter Wemm nmx--; 461c2aa98e2SPeter Wemm } 462c2aa98e2SPeter Wemm } 463c2aa98e2SPeter Wemm 464c2aa98e2SPeter Wemm if (nmx == 0) 465c2aa98e2SPeter Wemm { 466c2aa98e2SPeter Wemm punt: 46706f25ae9SGregory Neil Shapiro if (seenlocal) 468c2aa98e2SPeter Wemm { 46906f25ae9SGregory Neil Shapiro struct hostent *h = NULL; 47006f25ae9SGregory Neil Shapiro 471c2aa98e2SPeter Wemm /* 472c2aa98e2SPeter Wemm ** If we have deleted all MX entries, this is 473c2aa98e2SPeter Wemm ** an error -- we should NEVER send to a host that 474c2aa98e2SPeter Wemm ** has an MX, and this should have been caught 475c2aa98e2SPeter Wemm ** earlier in the config file. 476c2aa98e2SPeter Wemm ** 477c2aa98e2SPeter Wemm ** Some sites prefer to go ahead and try the 478c2aa98e2SPeter Wemm ** A record anyway; that case is handled by 479c2aa98e2SPeter Wemm ** setting TryNullMXList. I believe this is a 480c2aa98e2SPeter Wemm ** bad idea, but it's up to you.... 481c2aa98e2SPeter Wemm */ 482c2aa98e2SPeter Wemm 48306f25ae9SGregory Neil Shapiro if (TryNullMXList) 48406f25ae9SGregory Neil Shapiro { 485602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 48606f25ae9SGregory Neil Shapiro errno = 0; 48706f25ae9SGregory Neil Shapiro h = sm_gethostbyname(host, AF_INET); 48806f25ae9SGregory Neil Shapiro if (h == NULL) 48906f25ae9SGregory Neil Shapiro { 49006f25ae9SGregory Neil Shapiro if (errno == ETIMEDOUT || 49106f25ae9SGregory Neil Shapiro h_errno == TRY_AGAIN || 49206f25ae9SGregory Neil Shapiro (errno == ECONNREFUSED && 49306f25ae9SGregory Neil Shapiro UseNameServer)) 49406f25ae9SGregory Neil Shapiro { 49506f25ae9SGregory Neil Shapiro *rcode = EX_TEMPFAIL; 49606f25ae9SGregory Neil Shapiro return -1; 49706f25ae9SGregory Neil Shapiro } 49806f25ae9SGregory Neil Shapiro # if NETINET6 499602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 50006f25ae9SGregory Neil Shapiro errno = 0; 50106f25ae9SGregory Neil Shapiro h = sm_gethostbyname(host, AF_INET6); 50206f25ae9SGregory Neil Shapiro if (h == NULL && 50306f25ae9SGregory Neil Shapiro (errno == ETIMEDOUT || 50406f25ae9SGregory Neil Shapiro h_errno == TRY_AGAIN || 50506f25ae9SGregory Neil Shapiro (errno == ECONNREFUSED && 50606f25ae9SGregory Neil Shapiro UseNameServer))) 50706f25ae9SGregory Neil Shapiro { 50806f25ae9SGregory Neil Shapiro *rcode = EX_TEMPFAIL; 50906f25ae9SGregory Neil Shapiro return -1; 51006f25ae9SGregory Neil Shapiro } 51106f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 51206f25ae9SGregory Neil Shapiro } 51306f25ae9SGregory Neil Shapiro } 51406f25ae9SGregory Neil Shapiro 51506f25ae9SGregory Neil Shapiro if (h == NULL) 51606f25ae9SGregory Neil Shapiro { 517c2aa98e2SPeter Wemm *rcode = EX_CONFIG; 518c2aa98e2SPeter Wemm syserr("MX list for %s points back to %s", 519c2aa98e2SPeter Wemm host, MyHostName); 520c2aa98e2SPeter Wemm return -1; 521c2aa98e2SPeter Wemm } 52240266059SGregory Neil Shapiro # if NETINET6 523193538b7SGregory Neil Shapiro freehostent(h); 524193538b7SGregory Neil Shapiro hp = NULL; 52540266059SGregory Neil Shapiro # endif /* NETINET6 */ 52606f25ae9SGregory Neil Shapiro } 52740266059SGregory Neil Shapiro if (strlen(host) >= sizeof MXHostBuf) 528c2aa98e2SPeter Wemm { 529c2aa98e2SPeter Wemm *rcode = EX_CONFIG; 530c2aa98e2SPeter Wemm syserr("Host name %s too long", 531c2aa98e2SPeter Wemm shortenstring(host, MAXSHORTSTR)); 532c2aa98e2SPeter Wemm return -1; 533c2aa98e2SPeter Wemm } 53440266059SGregory Neil Shapiro (void) sm_strlcpy(MXHostBuf, host, sizeof MXHostBuf); 535c2aa98e2SPeter Wemm mxhosts[0] = MXHostBuf; 53606f25ae9SGregory Neil Shapiro prefs[0] = 0; 537c2aa98e2SPeter Wemm if (host[0] == '[') 538c2aa98e2SPeter Wemm { 539c2aa98e2SPeter Wemm register char *p; 54006f25ae9SGregory Neil Shapiro # if NETINET6 54106f25ae9SGregory Neil Shapiro struct sockaddr_in6 tmp6; 54206f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 543c2aa98e2SPeter Wemm 544c2aa98e2SPeter Wemm /* this may be an MX suppression-style address */ 545c2aa98e2SPeter Wemm p = strchr(MXHostBuf, ']'); 546c2aa98e2SPeter Wemm if (p != NULL) 547c2aa98e2SPeter Wemm { 548c2aa98e2SPeter Wemm *p = '\0'; 54906f25ae9SGregory Neil Shapiro 550c2aa98e2SPeter Wemm if (inet_addr(&MXHostBuf[1]) != INADDR_NONE) 551c2aa98e2SPeter Wemm { 552c2aa98e2SPeter Wemm nmx++; 553c2aa98e2SPeter Wemm *p = ']'; 554c2aa98e2SPeter Wemm } 55506f25ae9SGregory Neil Shapiro # if NETINET6 55640266059SGregory Neil Shapiro else if (anynet_pton(AF_INET6, &MXHostBuf[1], 55706f25ae9SGregory Neil Shapiro &tmp6.sin6_addr) == 1) 55806f25ae9SGregory Neil Shapiro { 55906f25ae9SGregory Neil Shapiro nmx++; 56006f25ae9SGregory Neil Shapiro *p = ']'; 56106f25ae9SGregory Neil Shapiro } 56206f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 563c2aa98e2SPeter Wemm else 564c2aa98e2SPeter Wemm { 56540266059SGregory Neil Shapiro trycanon = true; 566c2aa98e2SPeter Wemm mxhosts[0]++; 567c2aa98e2SPeter Wemm } 568c2aa98e2SPeter Wemm } 569c2aa98e2SPeter Wemm } 570c2aa98e2SPeter Wemm if (trycanon && 57140266059SGregory Neil Shapiro getcanonname(mxhosts[0], sizeof MXHostBuf - 2, false, pttl)) 572c2aa98e2SPeter Wemm { 57340266059SGregory Neil Shapiro /* XXX MXHostBuf == "" ? is that possible? */ 574c2aa98e2SPeter Wemm bp = &MXHostBuf[strlen(MXHostBuf)]; 575c2aa98e2SPeter Wemm if (bp[-1] != '.') 576c2aa98e2SPeter Wemm { 577c2aa98e2SPeter Wemm *bp++ = '.'; 578c2aa98e2SPeter Wemm *bp = '\0'; 579c2aa98e2SPeter Wemm } 580c2aa98e2SPeter Wemm nmx = 1; 581c2aa98e2SPeter Wemm } 582c2aa98e2SPeter Wemm } 583c2aa98e2SPeter Wemm 584c2aa98e2SPeter Wemm /* if we have a default lowest preference, include that */ 585c2aa98e2SPeter Wemm if (fallbackMX != NULL && !seenlocal) 58606f25ae9SGregory Neil Shapiro { 58740266059SGregory Neil Shapiro nmx = fallbackmxrr(nmx, prefs, mxhosts); 58806f25ae9SGregory Neil Shapiro } 58906f25ae9SGregory Neil Shapiro return nmx; 590c2aa98e2SPeter Wemm } 59140266059SGregory Neil Shapiro /* 592c2aa98e2SPeter Wemm ** MXRAND -- create a randomizer for equal MX preferences 593c2aa98e2SPeter Wemm ** 594c2aa98e2SPeter Wemm ** If two MX hosts have equal preferences we want to randomize 595c2aa98e2SPeter Wemm ** the selection. But in order for signatures to be the same, 596c2aa98e2SPeter Wemm ** we need to randomize the same way each time. This function 597c2aa98e2SPeter Wemm ** computes a pseudo-random hash function from the host name. 598c2aa98e2SPeter Wemm ** 599c2aa98e2SPeter Wemm ** Parameters: 600c2aa98e2SPeter Wemm ** host -- the name of the host. 601c2aa98e2SPeter Wemm ** 602c2aa98e2SPeter Wemm ** Returns: 603c2aa98e2SPeter Wemm ** A random but repeatable value based on the host name. 604c2aa98e2SPeter Wemm */ 605c2aa98e2SPeter Wemm 60606f25ae9SGregory Neil Shapiro static int 607c2aa98e2SPeter Wemm mxrand(host) 608c2aa98e2SPeter Wemm register char *host; 609c2aa98e2SPeter Wemm { 610c2aa98e2SPeter Wemm int hfunc; 611c2aa98e2SPeter Wemm static unsigned int seed; 612c2aa98e2SPeter Wemm 613c2aa98e2SPeter Wemm if (seed == 0) 614c2aa98e2SPeter Wemm { 615c2aa98e2SPeter Wemm seed = (int) curtime() & 0xffff; 616c2aa98e2SPeter Wemm if (seed == 0) 617c2aa98e2SPeter Wemm seed++; 618c2aa98e2SPeter Wemm } 619c2aa98e2SPeter Wemm 620c2aa98e2SPeter Wemm if (tTd(17, 9)) 62140266059SGregory Neil Shapiro sm_dprintf("mxrand(%s)", host); 622c2aa98e2SPeter Wemm 623c2aa98e2SPeter Wemm hfunc = seed; 624c2aa98e2SPeter Wemm while (*host != '\0') 625c2aa98e2SPeter Wemm { 626c2aa98e2SPeter Wemm int c = *host++; 627c2aa98e2SPeter Wemm 628c2aa98e2SPeter Wemm if (isascii(c) && isupper(c)) 629c2aa98e2SPeter Wemm c = tolower(c); 630c2aa98e2SPeter Wemm hfunc = ((hfunc << 1) ^ c) % 2003; 631c2aa98e2SPeter Wemm } 632c2aa98e2SPeter Wemm 633c2aa98e2SPeter Wemm hfunc &= 0xff; 634c2aa98e2SPeter Wemm hfunc++; 635c2aa98e2SPeter Wemm 636c2aa98e2SPeter Wemm if (tTd(17, 9)) 63740266059SGregory Neil Shapiro sm_dprintf(" = %d\n", hfunc); 638c2aa98e2SPeter Wemm return hfunc; 639c2aa98e2SPeter Wemm } 64040266059SGregory Neil Shapiro /* 641c2aa98e2SPeter Wemm ** BESTMX -- find the best MX for a name 642c2aa98e2SPeter Wemm ** 643c2aa98e2SPeter Wemm ** This is really a hack, but I don't see any obvious way 644c2aa98e2SPeter Wemm ** to generalize it at the moment. 645c2aa98e2SPeter Wemm */ 646c2aa98e2SPeter Wemm 647c2aa98e2SPeter Wemm /* ARGSUSED3 */ 648c2aa98e2SPeter Wemm char * 649c2aa98e2SPeter Wemm bestmx_map_lookup(map, name, av, statp) 650c2aa98e2SPeter Wemm MAP *map; 651c2aa98e2SPeter Wemm char *name; 652c2aa98e2SPeter Wemm char **av; 653c2aa98e2SPeter Wemm int *statp; 654c2aa98e2SPeter Wemm { 655c2aa98e2SPeter Wemm int nmx; 656c2aa98e2SPeter Wemm int saveopts = _res.options; 65740266059SGregory Neil Shapiro int i; 65840266059SGregory Neil Shapiro ssize_t len = 0; 65940266059SGregory Neil Shapiro char *result; 660c2aa98e2SPeter Wemm char *mxhosts[MAXMXHOSTS + 1]; 66140266059SGregory Neil Shapiro #if _FFR_BESTMX_BETTER_TRUNCATION 66240266059SGregory Neil Shapiro char *buf; 66340266059SGregory Neil Shapiro #else /* _FFR_BESTMX_BETTER_TRUNCATION */ 66440266059SGregory Neil Shapiro char *p; 665065a643dSPeter Wemm char buf[PSBUFSIZE / 2]; 66640266059SGregory Neil Shapiro #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 667c2aa98e2SPeter Wemm 668c2aa98e2SPeter Wemm _res.options &= ~(RES_DNSRCH|RES_DEFNAMES); 669959366dcSGregory Neil Shapiro nmx = getmxrr(name, mxhosts, NULL, false, statp, false, NULL); 670c2aa98e2SPeter Wemm _res.options = saveopts; 671c2aa98e2SPeter Wemm if (nmx <= 0) 672c2aa98e2SPeter Wemm return NULL; 673c2aa98e2SPeter Wemm if (bitset(MF_MATCHONLY, map->map_mflags)) 674c2aa98e2SPeter Wemm return map_rewrite(map, name, strlen(name), NULL); 675c2aa98e2SPeter Wemm if ((map->map_coldelim == '\0') || (nmx == 1)) 676c2aa98e2SPeter Wemm return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av); 677c2aa98e2SPeter Wemm 678c2aa98e2SPeter Wemm /* 679c2aa98e2SPeter Wemm ** We were given a -z flag (return all MXs) and there are multiple 680c2aa98e2SPeter Wemm ** ones. We need to build them all into a list. 681c2aa98e2SPeter Wemm */ 68240266059SGregory Neil Shapiro 68340266059SGregory Neil Shapiro #if _FFR_BESTMX_BETTER_TRUNCATION 68440266059SGregory Neil Shapiro for (i = 0; i < nmx; i++) 68540266059SGregory Neil Shapiro { 68640266059SGregory Neil Shapiro if (strchr(mxhosts[i], map->map_coldelim) != NULL) 68740266059SGregory Neil Shapiro { 68840266059SGregory Neil Shapiro syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 68940266059SGregory Neil Shapiro mxhosts[i], map->map_coldelim); 69040266059SGregory Neil Shapiro return NULL; 69140266059SGregory Neil Shapiro } 69240266059SGregory Neil Shapiro len += strlen(mxhosts[i]) + 1; 69340266059SGregory Neil Shapiro if (len < 0) 69440266059SGregory Neil Shapiro { 69540266059SGregory Neil Shapiro len -= strlen(mxhosts[i]) + 1; 69640266059SGregory Neil Shapiro break; 69740266059SGregory Neil Shapiro } 69840266059SGregory Neil Shapiro } 69940266059SGregory Neil Shapiro buf = (char *) sm_malloc(len); 70040266059SGregory Neil Shapiro if (buf == NULL) 70140266059SGregory Neil Shapiro { 70240266059SGregory Neil Shapiro *statp = EX_UNAVAILABLE; 70340266059SGregory Neil Shapiro return NULL; 70440266059SGregory Neil Shapiro } 70540266059SGregory Neil Shapiro *buf = '\0'; 70640266059SGregory Neil Shapiro for (i = 0; i < nmx; i++) 70740266059SGregory Neil Shapiro { 70840266059SGregory Neil Shapiro int end; 70940266059SGregory Neil Shapiro 71040266059SGregory Neil Shapiro end = sm_strlcat(buf, mxhosts[i], len); 71140266059SGregory Neil Shapiro if (i != nmx && end + 1 < len) 71240266059SGregory Neil Shapiro { 71340266059SGregory Neil Shapiro buf[end] = map->map_coldelim; 71440266059SGregory Neil Shapiro buf[end + 1] = '\0'; 71540266059SGregory Neil Shapiro } 71640266059SGregory Neil Shapiro } 71740266059SGregory Neil Shapiro 71840266059SGregory Neil Shapiro /* Cleanly truncate for rulesets */ 71940266059SGregory Neil Shapiro truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim); 72040266059SGregory Neil Shapiro #else /* _FFR_BESTMX_BETTER_TRUNCATION */ 721c2aa98e2SPeter Wemm p = buf; 722c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 723c2aa98e2SPeter Wemm { 72440266059SGregory Neil Shapiro size_t slen; 725c2aa98e2SPeter Wemm 726c2aa98e2SPeter Wemm if (strchr(mxhosts[i], map->map_coldelim) != NULL) 727c2aa98e2SPeter Wemm { 728c2aa98e2SPeter Wemm syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 729c2aa98e2SPeter Wemm mxhosts[i], map->map_coldelim); 730c2aa98e2SPeter Wemm return NULL; 731c2aa98e2SPeter Wemm } 732c2aa98e2SPeter Wemm slen = strlen(mxhosts[i]); 733c2aa98e2SPeter Wemm if (len + slen + 2 > sizeof buf) 734c2aa98e2SPeter Wemm break; 735c2aa98e2SPeter Wemm if (i > 0) 736c2aa98e2SPeter Wemm { 737c2aa98e2SPeter Wemm *p++ = map->map_coldelim; 738c2aa98e2SPeter Wemm len++; 739c2aa98e2SPeter Wemm } 74040266059SGregory Neil Shapiro (void) sm_strlcpy(p, mxhosts[i], sizeof buf - len); 741c2aa98e2SPeter Wemm p += slen; 742c2aa98e2SPeter Wemm len += slen; 743c2aa98e2SPeter Wemm } 74440266059SGregory Neil Shapiro #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 74540266059SGregory Neil Shapiro 74640266059SGregory Neil Shapiro result = map_rewrite(map, buf, len, av); 74740266059SGregory Neil Shapiro #if _FFR_BESTMX_BETTER_TRUNCATION 74840266059SGregory Neil Shapiro sm_free(buf); 74940266059SGregory Neil Shapiro #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 75040266059SGregory Neil Shapiro return result; 751c2aa98e2SPeter Wemm } 75240266059SGregory Neil Shapiro /* 753c2aa98e2SPeter Wemm ** DNS_GETCANONNAME -- get the canonical name for named host using DNS 754c2aa98e2SPeter Wemm ** 755c2aa98e2SPeter Wemm ** This algorithm tries to be smart about wildcard MX records. 756c2aa98e2SPeter Wemm ** This is hard to do because DNS doesn't tell is if we matched 757c2aa98e2SPeter Wemm ** against a wildcard or a specific MX. 758c2aa98e2SPeter Wemm ** 759c2aa98e2SPeter Wemm ** We always prefer A & CNAME records, since these are presumed 760c2aa98e2SPeter Wemm ** to be specific. 761c2aa98e2SPeter Wemm ** 762c2aa98e2SPeter Wemm ** If we match an MX in one pass and lose it in the next, we use 763c2aa98e2SPeter Wemm ** the old one. For example, consider an MX matching *.FOO.BAR.COM. 764c2aa98e2SPeter Wemm ** A hostname bletch.foo.bar.com will match against this MX, but 765c2aa98e2SPeter Wemm ** will stop matching when we try bletch.bar.com -- so we know 766c2aa98e2SPeter Wemm ** that bletch.foo.bar.com must have been right. This fails if 767c2aa98e2SPeter Wemm ** there was also an MX record matching *.BAR.COM, but there are 768c2aa98e2SPeter Wemm ** some things that just can't be fixed. 769c2aa98e2SPeter Wemm ** 770c2aa98e2SPeter Wemm ** Parameters: 771c2aa98e2SPeter Wemm ** host -- a buffer containing the name of the host. 772c2aa98e2SPeter Wemm ** This is a value-result parameter. 773c2aa98e2SPeter Wemm ** hbsize -- the size of the host buffer. 774c2aa98e2SPeter Wemm ** trymx -- if set, try MX records as well as A and CNAME. 775c2aa98e2SPeter Wemm ** statp -- pointer to place to store status. 77640266059SGregory Neil Shapiro ** pttl -- pointer to return TTL (can be NULL). 777c2aa98e2SPeter Wemm ** 778c2aa98e2SPeter Wemm ** Returns: 77940266059SGregory Neil Shapiro ** true -- if the host matched. 78040266059SGregory Neil Shapiro ** false -- otherwise. 781c2aa98e2SPeter Wemm */ 782c2aa98e2SPeter Wemm 783c2aa98e2SPeter Wemm bool 78440266059SGregory Neil Shapiro dns_getcanonname(host, hbsize, trymx, statp, pttl) 785c2aa98e2SPeter Wemm char *host; 786c2aa98e2SPeter Wemm int hbsize; 787c2aa98e2SPeter Wemm bool trymx; 788c2aa98e2SPeter Wemm int *statp; 78940266059SGregory Neil Shapiro int *pttl; 790c2aa98e2SPeter Wemm { 79140266059SGregory Neil Shapiro register unsigned char *eom, *ap; 792c2aa98e2SPeter Wemm register char *cp; 793c2aa98e2SPeter Wemm register int n; 794c2aa98e2SPeter Wemm HEADER *hp; 795c2aa98e2SPeter Wemm querybuf answer; 796c2aa98e2SPeter Wemm int ancount, qdcount; 797c2aa98e2SPeter Wemm int ret; 798c2aa98e2SPeter Wemm char **domain; 799c2aa98e2SPeter Wemm int type; 80040266059SGregory Neil Shapiro int ttl = 0; 801c2aa98e2SPeter Wemm char **dp; 802c2aa98e2SPeter Wemm char *mxmatch; 803c2aa98e2SPeter Wemm bool amatch; 80440266059SGregory Neil Shapiro bool gotmx = false; 805c2aa98e2SPeter Wemm int qtype; 806a7ec597cSGregory Neil Shapiro int initial; 807c2aa98e2SPeter Wemm int loopcnt; 808c2aa98e2SPeter Wemm char *xp; 80940266059SGregory Neil Shapiro char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)]; 810c2aa98e2SPeter Wemm char *searchlist[MAXDNSRCH + 2]; 811c2aa98e2SPeter Wemm 812c2aa98e2SPeter Wemm if (tTd(8, 2)) 81340266059SGregory Neil Shapiro sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx); 814c2aa98e2SPeter Wemm 815c2aa98e2SPeter Wemm if ((_res.options & RES_INIT) == 0 && res_init() == -1) 816c2aa98e2SPeter Wemm { 817c2aa98e2SPeter Wemm *statp = EX_UNAVAILABLE; 81840266059SGregory Neil Shapiro return false; 819c2aa98e2SPeter Wemm } 820c2aa98e2SPeter Wemm 821193538b7SGregory Neil Shapiro *statp = EX_OK; 822193538b7SGregory Neil Shapiro 823c2aa98e2SPeter Wemm /* 824c2aa98e2SPeter Wemm ** Initialize domain search list. If there is at least one 825c2aa98e2SPeter Wemm ** dot in the name, search the unmodified name first so we 826c2aa98e2SPeter Wemm ** find "vse.CS" in Czechoslovakia instead of in the local 82706f25ae9SGregory Neil Shapiro ** domain (e.g., vse.CS.Berkeley.EDU). Note that there is no 82806f25ae9SGregory Neil Shapiro ** longer a country named Czechoslovakia but this type of problem 82906f25ae9SGregory Neil Shapiro ** is still present. 830c2aa98e2SPeter Wemm ** 831c2aa98e2SPeter Wemm ** Older versions of the resolver could create this 832c2aa98e2SPeter Wemm ** list by tearing apart the host name. 833c2aa98e2SPeter Wemm */ 834c2aa98e2SPeter Wemm 835c2aa98e2SPeter Wemm loopcnt = 0; 836c2aa98e2SPeter Wemm cnameloop: 837c2aa98e2SPeter Wemm /* Check for dots in the name */ 838c2aa98e2SPeter Wemm for (cp = host, n = 0; *cp != '\0'; cp++) 839c2aa98e2SPeter Wemm if (*cp == '.') 840c2aa98e2SPeter Wemm n++; 841c2aa98e2SPeter Wemm 842c2aa98e2SPeter Wemm /* 843c2aa98e2SPeter Wemm ** If this is a simple name, determine whether it matches an 844c2aa98e2SPeter Wemm ** alias in the file defined by the environment variable HOSTALIASES. 845c2aa98e2SPeter Wemm */ 84640266059SGregory Neil Shapiro 847c2aa98e2SPeter Wemm if (n == 0 && (xp = gethostalias(host)) != NULL) 848c2aa98e2SPeter Wemm { 849c2aa98e2SPeter Wemm if (loopcnt++ > MAXCNAMEDEPTH) 850c2aa98e2SPeter Wemm { 851c2aa98e2SPeter Wemm syserr("loop in ${HOSTALIASES} file"); 852c2aa98e2SPeter Wemm } 853c2aa98e2SPeter Wemm else 854c2aa98e2SPeter Wemm { 85540266059SGregory Neil Shapiro (void) sm_strlcpy(host, xp, hbsize); 856c2aa98e2SPeter Wemm goto cnameloop; 857c2aa98e2SPeter Wemm } 858c2aa98e2SPeter Wemm } 859c2aa98e2SPeter Wemm 860c2aa98e2SPeter Wemm /* 861c2aa98e2SPeter Wemm ** Build the search list. 862c2aa98e2SPeter Wemm ** If there is at least one dot in name, start with a null 863c2aa98e2SPeter Wemm ** domain to search the unmodified name first. 864c2aa98e2SPeter Wemm ** If name does not end with a dot and search up local domain 865c2aa98e2SPeter Wemm ** tree desired, append each local domain component to the 866c2aa98e2SPeter Wemm ** search list; if name contains no dots and default domain 867c2aa98e2SPeter Wemm ** name is desired, append default domain name to search list; 868c2aa98e2SPeter Wemm ** else if name ends in a dot, remove that dot. 869c2aa98e2SPeter Wemm */ 870c2aa98e2SPeter Wemm 871c2aa98e2SPeter Wemm dp = searchlist; 872c2aa98e2SPeter Wemm if (n > 0) 873c2aa98e2SPeter Wemm *dp++ = ""; 874c2aa98e2SPeter Wemm if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options)) 875c2aa98e2SPeter Wemm { 87606f25ae9SGregory Neil Shapiro /* make sure there are less than MAXDNSRCH domains */ 87706f25ae9SGregory Neil Shapiro for (domain = RES_DNSRCH_VARIABLE, ret = 0; 87806f25ae9SGregory Neil Shapiro *domain != NULL && ret < MAXDNSRCH; 87906f25ae9SGregory Neil Shapiro ret++) 880c2aa98e2SPeter Wemm *dp++ = *domain++; 881c2aa98e2SPeter Wemm } 882c2aa98e2SPeter Wemm else if (n == 0 && bitset(RES_DEFNAMES, _res.options)) 883c2aa98e2SPeter Wemm { 884c2aa98e2SPeter Wemm *dp++ = _res.defdname; 885c2aa98e2SPeter Wemm } 886c2aa98e2SPeter Wemm else if (*cp == '.') 887c2aa98e2SPeter Wemm { 888c2aa98e2SPeter Wemm *cp = '\0'; 889c2aa98e2SPeter Wemm } 890c2aa98e2SPeter Wemm *dp = NULL; 891c2aa98e2SPeter Wemm 892c2aa98e2SPeter Wemm /* 893c2aa98e2SPeter Wemm ** Now loop through the search list, appending each domain in turn 894c2aa98e2SPeter Wemm ** name and searching for a match. 895c2aa98e2SPeter Wemm */ 896c2aa98e2SPeter Wemm 897c2aa98e2SPeter Wemm mxmatch = NULL; 898a7ec597cSGregory Neil Shapiro initial = T_A; 899a7ec597cSGregory Neil Shapiro # if NETINET6 900a7ec597cSGregory Neil Shapiro if (InetMode == AF_INET6) 901a7ec597cSGregory Neil Shapiro initial = T_AAAA; 902a7ec597cSGregory Neil Shapiro # endif /* NETINET6 */ 903a7ec597cSGregory Neil Shapiro qtype = initial; 904c2aa98e2SPeter Wemm 905c2aa98e2SPeter Wemm for (dp = searchlist; *dp != NULL; ) 906c2aa98e2SPeter Wemm { 907a7ec597cSGregory Neil Shapiro if (qtype == initial) 90840266059SGregory Neil Shapiro gotmx = false; 909c2aa98e2SPeter Wemm if (tTd(8, 5)) 91040266059SGregory Neil Shapiro sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n", 911c2aa98e2SPeter Wemm host, *dp, 91206f25ae9SGregory Neil Shapiro # if NETINET6 91306f25ae9SGregory Neil Shapiro qtype == T_AAAA ? "AAAA" : 91406f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 91506f25ae9SGregory Neil Shapiro qtype == T_A ? "A" : 91606f25ae9SGregory Neil Shapiro qtype == T_MX ? "MX" : 91706f25ae9SGregory Neil Shapiro "???"); 918193538b7SGregory Neil Shapiro errno = 0; 919c2aa98e2SPeter Wemm ret = res_querydomain(host, *dp, C_IN, qtype, 920c2aa98e2SPeter Wemm answer.qb2, sizeof(answer.qb2)); 921c2aa98e2SPeter Wemm if (ret <= 0) 922c2aa98e2SPeter Wemm { 92340266059SGregory Neil Shapiro int save_errno = errno; 924c2aa98e2SPeter Wemm 92540266059SGregory Neil Shapiro if (tTd(8, 7)) 92640266059SGregory Neil Shapiro sm_dprintf("\tNO: errno=%d, h_errno=%d\n", 92740266059SGregory Neil Shapiro save_errno, h_errno); 92840266059SGregory Neil Shapiro 92940266059SGregory Neil Shapiro if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN) 930c2aa98e2SPeter Wemm { 931193538b7SGregory Neil Shapiro /* 93240266059SGregory Neil Shapiro ** the name server seems to be down or broken. 933193538b7SGregory Neil Shapiro */ 934193538b7SGregory Neil Shapiro 935602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(TRY_AGAIN); 936605302a5SGregory Neil Shapiro # if _FFR_DONT_STOP_LOOKING 937605302a5SGregory Neil Shapiro if (**dp == '\0') 938605302a5SGregory Neil Shapiro { 939605302a5SGregory Neil Shapiro if (*statp == EX_OK) 940605302a5SGregory Neil Shapiro *statp = EX_TEMPFAIL; 941605302a5SGregory Neil Shapiro goto nexttype; 942605302a5SGregory Neil Shapiro } 943605302a5SGregory Neil Shapiro # endif /* _FFR_DONT_STOP_LOOKING */ 944c2aa98e2SPeter Wemm *statp = EX_TEMPFAIL; 94506f25ae9SGregory Neil Shapiro 946602a2b1bSGregory Neil Shapiro if (WorkAroundBrokenAAAA) 947602a2b1bSGregory Neil Shapiro { 948193538b7SGregory Neil Shapiro /* 949193538b7SGregory Neil Shapiro ** Only return if not TRY_AGAIN as an 950193538b7SGregory Neil Shapiro ** attempt with a different qtype may 951193538b7SGregory Neil Shapiro ** succeed (res_querydomain() calls 952193538b7SGregory Neil Shapiro ** res_query() calls res_send() which 953193538b7SGregory Neil Shapiro ** sets errno to ETIMEDOUT if the 954193538b7SGregory Neil Shapiro ** nameservers could be contacted but 955193538b7SGregory Neil Shapiro ** didn't give an answer). 956193538b7SGregory Neil Shapiro */ 957193538b7SGregory Neil Shapiro 95840266059SGregory Neil Shapiro if (save_errno != ETIMEDOUT) 95940266059SGregory Neil Shapiro return false; 960602a2b1bSGregory Neil Shapiro } 96140266059SGregory Neil Shapiro else 96240266059SGregory Neil Shapiro return false; 963c2aa98e2SPeter Wemm } 964c2aa98e2SPeter Wemm 965605302a5SGregory Neil Shapiro # if _FFR_DONT_STOP_LOOKING 966605302a5SGregory Neil Shapiro nexttype: 967605302a5SGregory Neil Shapiro # endif /* _FFR_DONT_STOP_LOOKING */ 968c2aa98e2SPeter Wemm if (h_errno != HOST_NOT_FOUND) 969c2aa98e2SPeter Wemm { 970c2aa98e2SPeter Wemm /* might have another type of interest */ 97106f25ae9SGregory Neil Shapiro # if NETINET6 97240266059SGregory Neil Shapiro if (qtype == T_AAAA) 97306f25ae9SGregory Neil Shapiro { 974c2aa98e2SPeter Wemm qtype = T_A; 975c2aa98e2SPeter Wemm continue; 976c2aa98e2SPeter Wemm } 97740266059SGregory Neil Shapiro else 97806f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 97940266059SGregory Neil Shapiro if (qtype == T_A && !gotmx && 98006f25ae9SGregory Neil Shapiro (trymx || **dp == '\0')) 981c2aa98e2SPeter Wemm { 982c2aa98e2SPeter Wemm qtype = T_MX; 983c2aa98e2SPeter Wemm continue; 984c2aa98e2SPeter Wemm } 985c2aa98e2SPeter Wemm } 986c2aa98e2SPeter Wemm 987c2aa98e2SPeter Wemm /* definite no -- try the next domain */ 988c2aa98e2SPeter Wemm dp++; 989a7ec597cSGregory Neil Shapiro qtype = initial; 990c2aa98e2SPeter Wemm continue; 991c2aa98e2SPeter Wemm } 992c2aa98e2SPeter Wemm else if (tTd(8, 7)) 99340266059SGregory Neil Shapiro sm_dprintf("\tYES\n"); 994c2aa98e2SPeter Wemm 995c2aa98e2SPeter Wemm /* avoid problems after truncation in tcp packets */ 996c2aa98e2SPeter Wemm if (ret > sizeof(answer)) 997c2aa98e2SPeter Wemm ret = sizeof(answer); 99840266059SGregory Neil Shapiro if (ret < 0) 99940266059SGregory Neil Shapiro { 100040266059SGregory Neil Shapiro *statp = EX_SOFTWARE; 100140266059SGregory Neil Shapiro return false; 100240266059SGregory Neil Shapiro } 1003c2aa98e2SPeter Wemm 1004c2aa98e2SPeter Wemm /* 1005c2aa98e2SPeter Wemm ** Appear to have a match. Confirm it by searching for A or 1006c2aa98e2SPeter Wemm ** CNAME records. If we don't have a local domain 1007c2aa98e2SPeter Wemm ** wild card MX record, we will accept MX as well. 1008c2aa98e2SPeter Wemm */ 1009c2aa98e2SPeter Wemm 1010c2aa98e2SPeter Wemm hp = (HEADER *) &answer; 101140266059SGregory Neil Shapiro ap = (unsigned char *) &answer + HFIXEDSZ; 101240266059SGregory Neil Shapiro eom = (unsigned char *) &answer + ret; 1013c2aa98e2SPeter Wemm 1014c2aa98e2SPeter Wemm /* skip question part of response -- we know what we asked */ 101540266059SGregory Neil Shapiro for (qdcount = ntohs((unsigned short) hp->qdcount); 101606f25ae9SGregory Neil Shapiro qdcount--; 101706f25ae9SGregory Neil Shapiro ap += ret + QFIXEDSZ) 1018c2aa98e2SPeter Wemm { 1019c2aa98e2SPeter Wemm if ((ret = dn_skipname(ap, eom)) < 0) 1020c2aa98e2SPeter Wemm { 1021c2aa98e2SPeter Wemm if (tTd(8, 20)) 102240266059SGregory Neil Shapiro sm_dprintf("qdcount failure (%d)\n", 102340266059SGregory Neil Shapiro ntohs((unsigned short) hp->qdcount)); 1024c2aa98e2SPeter Wemm *statp = EX_SOFTWARE; 102540266059SGregory Neil Shapiro return false; /* ???XXX??? */ 1026c2aa98e2SPeter Wemm } 1027c2aa98e2SPeter Wemm } 1028c2aa98e2SPeter Wemm 102940266059SGregory Neil Shapiro amatch = false; 103040266059SGregory Neil Shapiro for (ancount = ntohs((unsigned short) hp->ancount); 103106f25ae9SGregory Neil Shapiro --ancount >= 0 && ap < eom; 1032c2aa98e2SPeter Wemm ap += n) 1033c2aa98e2SPeter Wemm { 103440266059SGregory Neil Shapiro n = dn_expand((unsigned char *) &answer, eom, ap, 1035c2aa98e2SPeter Wemm (RES_UNC_T) nbuf, sizeof nbuf); 1036c2aa98e2SPeter Wemm if (n < 0) 1037c2aa98e2SPeter Wemm break; 1038c2aa98e2SPeter Wemm ap += n; 1039c2aa98e2SPeter Wemm GETSHORT(type, ap); 104040266059SGregory Neil Shapiro ap += INT16SZ; /* skip over class */ 104140266059SGregory Neil Shapiro GETLONG(ttl, ap); 104240266059SGregory Neil Shapiro GETSHORT(n, ap); /* rdlength */ 1043c2aa98e2SPeter Wemm switch (type) 1044c2aa98e2SPeter Wemm { 1045c2aa98e2SPeter Wemm case T_MX: 104640266059SGregory Neil Shapiro gotmx = true; 1047c2aa98e2SPeter Wemm if (**dp != '\0' && HasWildcardMX) 1048c2aa98e2SPeter Wemm { 1049c2aa98e2SPeter Wemm /* 1050c2aa98e2SPeter Wemm ** If we are using MX matches and have 1051c2aa98e2SPeter Wemm ** not yet gotten one, save this one 1052c2aa98e2SPeter Wemm ** but keep searching for an A or 1053c2aa98e2SPeter Wemm ** CNAME match. 1054c2aa98e2SPeter Wemm */ 1055c2aa98e2SPeter Wemm 1056c2aa98e2SPeter Wemm if (trymx && mxmatch == NULL) 1057c2aa98e2SPeter Wemm mxmatch = *dp; 1058c2aa98e2SPeter Wemm continue; 1059c2aa98e2SPeter Wemm } 1060c2aa98e2SPeter Wemm 1061c2aa98e2SPeter Wemm /* 1062c2aa98e2SPeter Wemm ** If we did not append a domain name, this 1063c2aa98e2SPeter Wemm ** must have been a canonical name to start 1064c2aa98e2SPeter Wemm ** with. Even if we did append a domain name, 1065c2aa98e2SPeter Wemm ** in the absence of a wildcard MX this must 1066c2aa98e2SPeter Wemm ** still be a real MX match. 1067c2aa98e2SPeter Wemm ** Such MX matches are as good as an A match, 1068c2aa98e2SPeter Wemm ** fall through. 1069c2aa98e2SPeter Wemm */ 107006f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 107106f25ae9SGregory Neil Shapiro 107206f25ae9SGregory Neil Shapiro # if NETINET6 107306f25ae9SGregory Neil Shapiro case T_AAAA: 107406f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 1075c2aa98e2SPeter Wemm case T_A: 1076c2aa98e2SPeter Wemm /* Flag that a good match was found */ 107740266059SGregory Neil Shapiro amatch = true; 1078c2aa98e2SPeter Wemm 1079c2aa98e2SPeter Wemm /* continue in case a CNAME also exists */ 1080c2aa98e2SPeter Wemm continue; 1081c2aa98e2SPeter Wemm 1082c2aa98e2SPeter Wemm case T_CNAME: 1083c2aa98e2SPeter Wemm if (DontExpandCnames) 1084c2aa98e2SPeter Wemm { 1085c2aa98e2SPeter Wemm /* got CNAME -- guaranteed canonical */ 108640266059SGregory Neil Shapiro amatch = true; 1087c2aa98e2SPeter Wemm break; 1088c2aa98e2SPeter Wemm } 1089c2aa98e2SPeter Wemm 1090c2aa98e2SPeter Wemm if (loopcnt++ > MAXCNAMEDEPTH) 1091c2aa98e2SPeter Wemm { 1092c2aa98e2SPeter Wemm /*XXX should notify postmaster XXX*/ 1093c2aa98e2SPeter Wemm message("DNS failure: CNAME loop for %s", 1094c2aa98e2SPeter Wemm host); 1095c2aa98e2SPeter Wemm if (CurEnv->e_message == NULL) 1096c2aa98e2SPeter Wemm { 1097c2aa98e2SPeter Wemm char ebuf[MAXLINE]; 1098c2aa98e2SPeter Wemm 109940266059SGregory Neil Shapiro (void) sm_snprintf(ebuf, 110040266059SGregory Neil Shapiro sizeof ebuf, 1101c2aa98e2SPeter Wemm "Deferred: DNS failure: CNAME loop for %.100s", 1102c2aa98e2SPeter Wemm host); 110340266059SGregory Neil Shapiro CurEnv->e_message = 110440266059SGregory Neil Shapiro sm_rpool_strdup_x( 110540266059SGregory Neil Shapiro CurEnv->e_rpool, ebuf); 1106c2aa98e2SPeter Wemm } 1107602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(NO_RECOVERY); 1108c2aa98e2SPeter Wemm *statp = EX_CONFIG; 110940266059SGregory Neil Shapiro return false; 1110c2aa98e2SPeter Wemm } 1111c2aa98e2SPeter Wemm 1112c2aa98e2SPeter Wemm /* value points at name */ 111340266059SGregory Neil Shapiro if ((ret = dn_expand((unsigned char *)&answer, 111440266059SGregory Neil Shapiro eom, ap, (RES_UNC_T) nbuf, 111540266059SGregory Neil Shapiro sizeof(nbuf))) < 0) 1116c2aa98e2SPeter Wemm break; 111740266059SGregory Neil Shapiro (void) sm_strlcpy(host, nbuf, hbsize); 1118c2aa98e2SPeter Wemm 1119c2aa98e2SPeter Wemm /* 1120c2aa98e2SPeter Wemm ** RFC 1034 section 3.6 specifies that CNAME 1121c2aa98e2SPeter Wemm ** should point at the canonical name -- but 1122c2aa98e2SPeter Wemm ** urges software to try again anyway. 1123c2aa98e2SPeter Wemm */ 1124c2aa98e2SPeter Wemm 1125c2aa98e2SPeter Wemm goto cnameloop; 1126c2aa98e2SPeter Wemm 1127c2aa98e2SPeter Wemm default: 1128c2aa98e2SPeter Wemm /* not a record of interest */ 1129c2aa98e2SPeter Wemm continue; 1130c2aa98e2SPeter Wemm } 1131c2aa98e2SPeter Wemm } 1132c2aa98e2SPeter Wemm 1133c2aa98e2SPeter Wemm if (amatch) 1134c2aa98e2SPeter Wemm { 1135c2aa98e2SPeter Wemm /* 1136c2aa98e2SPeter Wemm ** Got a good match -- either an A, CNAME, or an 1137c2aa98e2SPeter Wemm ** exact MX record. Save it and get out of here. 1138c2aa98e2SPeter Wemm */ 1139c2aa98e2SPeter Wemm 1140c2aa98e2SPeter Wemm mxmatch = *dp; 1141c2aa98e2SPeter Wemm break; 1142c2aa98e2SPeter Wemm } 1143c2aa98e2SPeter Wemm 1144c2aa98e2SPeter Wemm /* 1145c2aa98e2SPeter Wemm ** Nothing definitive yet. 1146c2aa98e2SPeter Wemm ** If this was a T_A query and we haven't yet found a MX 1147c2aa98e2SPeter Wemm ** match, try T_MX if allowed to do so. 1148c2aa98e2SPeter Wemm ** Otherwise, try the next domain. 1149c2aa98e2SPeter Wemm */ 1150c2aa98e2SPeter Wemm 115106f25ae9SGregory Neil Shapiro # if NETINET6 115240266059SGregory Neil Shapiro if (qtype == T_AAAA) 1153c2aa98e2SPeter Wemm qtype = T_A; 115440266059SGregory Neil Shapiro else 115506f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 115640266059SGregory Neil Shapiro if (qtype == T_A && !gotmx && (trymx || **dp == '\0')) 1157c2aa98e2SPeter Wemm qtype = T_MX; 1158c2aa98e2SPeter Wemm else 1159c2aa98e2SPeter Wemm { 1160a7ec597cSGregory Neil Shapiro qtype = initial; 1161c2aa98e2SPeter Wemm dp++; 1162c2aa98e2SPeter Wemm } 1163c2aa98e2SPeter Wemm } 1164c2aa98e2SPeter Wemm 1165c2aa98e2SPeter Wemm /* if nothing was found, we are done */ 1166c2aa98e2SPeter Wemm if (mxmatch == NULL) 1167c2aa98e2SPeter Wemm { 1168193538b7SGregory Neil Shapiro if (*statp == EX_OK) 1169c2aa98e2SPeter Wemm *statp = EX_NOHOST; 117040266059SGregory Neil Shapiro return false; 1171c2aa98e2SPeter Wemm } 1172c2aa98e2SPeter Wemm 1173c2aa98e2SPeter Wemm /* 1174c2aa98e2SPeter Wemm ** Create canonical name and return. 1175c2aa98e2SPeter Wemm ** If saved domain name is null, name was already canonical. 1176c2aa98e2SPeter Wemm ** Otherwise append the saved domain name. 1177c2aa98e2SPeter Wemm */ 1178c2aa98e2SPeter Wemm 117940266059SGregory Neil Shapiro (void) sm_snprintf(nbuf, sizeof nbuf, "%.*s%s%.*s", MAXDNAME, host, 1180c2aa98e2SPeter Wemm *mxmatch == '\0' ? "" : ".", 1181c2aa98e2SPeter Wemm MAXDNAME, mxmatch); 118240266059SGregory Neil Shapiro (void) sm_strlcpy(host, nbuf, hbsize); 1183c2aa98e2SPeter Wemm if (tTd(8, 5)) 118440266059SGregory Neil Shapiro sm_dprintf("dns_getcanonname: %s\n", host); 1185c2aa98e2SPeter Wemm *statp = EX_OK; 118640266059SGregory Neil Shapiro 118740266059SGregory Neil Shapiro /* return only one TTL entry, that should be sufficient */ 118840266059SGregory Neil Shapiro if (ttl > 0 && pttl != NULL) 118940266059SGregory Neil Shapiro *pttl = ttl; 119040266059SGregory Neil Shapiro return true; 1191c2aa98e2SPeter Wemm } 1192c2aa98e2SPeter Wemm 119306f25ae9SGregory Neil Shapiro static char * 1194c2aa98e2SPeter Wemm gethostalias(host) 1195c2aa98e2SPeter Wemm char *host; 1196c2aa98e2SPeter Wemm { 1197c2aa98e2SPeter Wemm char *fname; 119840266059SGregory Neil Shapiro SM_FILE_T *fp; 1199c2aa98e2SPeter Wemm register char *p = NULL; 120006f25ae9SGregory Neil Shapiro long sff = SFF_REGONLY; 1201c2aa98e2SPeter Wemm char buf[MAXLINE]; 1202c2aa98e2SPeter Wemm static char hbuf[MAXDNAME]; 1203c2aa98e2SPeter Wemm 120440266059SGregory Neil Shapiro if (ResNoAliases) 120540266059SGregory Neil Shapiro return NULL; 1206c2aa98e2SPeter Wemm if (DontLockReadFiles) 1207c2aa98e2SPeter Wemm sff |= SFF_NOLOCK; 1208c2aa98e2SPeter Wemm fname = getenv("HOSTALIASES"); 1209c2aa98e2SPeter Wemm if (fname == NULL || 1210c2aa98e2SPeter Wemm (fp = safefopen(fname, O_RDONLY, 0, sff)) == NULL) 1211c2aa98e2SPeter Wemm return NULL; 121240266059SGregory Neil Shapiro while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) 1213c2aa98e2SPeter Wemm { 1214c2aa98e2SPeter Wemm for (p = buf; p != '\0' && !(isascii(*p) && isspace(*p)); p++) 1215c2aa98e2SPeter Wemm continue; 1216c2aa98e2SPeter Wemm if (*p == 0) 1217c2aa98e2SPeter Wemm { 1218c2aa98e2SPeter Wemm /* syntax error */ 1219c2aa98e2SPeter Wemm continue; 1220c2aa98e2SPeter Wemm } 1221c2aa98e2SPeter Wemm *p++ = '\0'; 122240266059SGregory Neil Shapiro if (sm_strcasecmp(buf, host) == 0) 1223c2aa98e2SPeter Wemm break; 1224c2aa98e2SPeter Wemm } 1225c2aa98e2SPeter Wemm 122640266059SGregory Neil Shapiro if (sm_io_eof(fp)) 1227c2aa98e2SPeter Wemm { 1228c2aa98e2SPeter Wemm /* no match */ 122940266059SGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 1230c2aa98e2SPeter Wemm return NULL; 1231c2aa98e2SPeter Wemm } 123240266059SGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 1233c2aa98e2SPeter Wemm 1234c2aa98e2SPeter Wemm /* got a match; extract the equivalent name */ 1235c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 1236c2aa98e2SPeter Wemm p++; 1237c2aa98e2SPeter Wemm host = p; 1238c2aa98e2SPeter Wemm while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1239c2aa98e2SPeter Wemm p++; 1240c2aa98e2SPeter Wemm *p = '\0'; 124140266059SGregory Neil Shapiro (void) sm_strlcpy(hbuf, host, sizeof hbuf); 1242c2aa98e2SPeter Wemm return hbuf; 1243c2aa98e2SPeter Wemm } 1244c2aa98e2SPeter Wemm #endif /* NAMED_BIND */ 1245