1c2aa98e2SPeter Wemm /* 2602a2b1bSGregory Neil Shapiro * Copyright (c) 1998-2001 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 1740266059SGregory Neil Shapiro SM_RCSID("@(#)$Id: domain.c,v 8.177 2001/12/12 01:16:15 ca Exp $ (with name server)") 1806f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */ 1940266059SGregory Neil Shapiro SM_RCSID("@(#)$Id: domain.c,v 8.177 2001/12/12 01:16:15 ca 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); 236c2aa98e2SPeter Wemm 23740266059SGregory Neil Shapiro if ((fallbackMX != NULL && droplocalhost && 23840266059SGregory Neil Shapiro wordinclass(fallbackMX, 'w')) || !tryfallback) 239c2aa98e2SPeter Wemm { 240c2aa98e2SPeter Wemm /* don't use fallback for this pass */ 241c2aa98e2SPeter Wemm fallbackMX = NULL; 242c2aa98e2SPeter Wemm } 243c2aa98e2SPeter Wemm 244c2aa98e2SPeter Wemm *rcode = EX_OK; 245c2aa98e2SPeter Wemm 24606f25ae9SGregory Neil Shapiro if (mxprefs != NULL) 24706f25ae9SGregory Neil Shapiro prefs = mxprefs; 24806f25ae9SGregory Neil Shapiro else 24906f25ae9SGregory Neil Shapiro prefs = prefer; 25006f25ae9SGregory Neil Shapiro 251c2aa98e2SPeter Wemm /* efficiency hack -- numeric or non-MX lookups */ 252c2aa98e2SPeter Wemm if (host[0] == '[') 253c2aa98e2SPeter Wemm goto punt; 254c2aa98e2SPeter Wemm 255c2aa98e2SPeter Wemm /* 256c2aa98e2SPeter Wemm ** If we don't have MX records in our host switch, don't 257c2aa98e2SPeter Wemm ** try for MX records. Note that this really isn't "right", 258c2aa98e2SPeter Wemm ** since we might be set up to try NIS first and then DNS; 259c2aa98e2SPeter Wemm ** if the host is found in NIS we really shouldn't be doing 260c2aa98e2SPeter Wemm ** MX lookups. However, that should be a degenerate case. 261c2aa98e2SPeter Wemm */ 262c2aa98e2SPeter Wemm 263c2aa98e2SPeter Wemm if (!UseNameServer) 264c2aa98e2SPeter Wemm goto punt; 265c2aa98e2SPeter Wemm if (HasWildcardMX && ConfigLevel >= 6) 266c2aa98e2SPeter Wemm resfunc = res_query; 267c2aa98e2SPeter Wemm else 268c2aa98e2SPeter Wemm resfunc = res_search; 269c2aa98e2SPeter Wemm 270c2aa98e2SPeter Wemm errno = 0; 27140266059SGregory Neil Shapiro n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer, 27240266059SGregory Neil Shapiro sizeof(answer)); 273c2aa98e2SPeter Wemm if (n < 0) 274c2aa98e2SPeter Wemm { 275c2aa98e2SPeter Wemm if (tTd(8, 1)) 27640266059SGregory Neil Shapiro sm_dprintf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n", 27740266059SGregory Neil Shapiro host == NULL ? "<NULL>" : host, errno, h_errno); 278c2aa98e2SPeter Wemm switch (h_errno) 279c2aa98e2SPeter Wemm { 280c2aa98e2SPeter Wemm case NO_DATA: 28140266059SGregory Neil Shapiro trycanon = true; 28206f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 283c2aa98e2SPeter Wemm 284c2aa98e2SPeter Wemm case NO_RECOVERY: 285c2aa98e2SPeter Wemm /* no MX data on this host */ 286c2aa98e2SPeter Wemm goto punt; 287c2aa98e2SPeter Wemm 288c2aa98e2SPeter Wemm case HOST_NOT_FOUND: 289c2aa98e2SPeter Wemm # if BROKEN_RES_SEARCH 290c2aa98e2SPeter Wemm case 0: /* Ultrix resolver retns failure w/ h_errno=0 */ 29106f25ae9SGregory Neil Shapiro # endif /* BROKEN_RES_SEARCH */ 292c2aa98e2SPeter Wemm /* host doesn't exist in DNS; might be in /etc/hosts */ 29340266059SGregory Neil Shapiro trycanon = true; 294c2aa98e2SPeter Wemm *rcode = EX_NOHOST; 295c2aa98e2SPeter Wemm goto punt; 296c2aa98e2SPeter Wemm 297c2aa98e2SPeter Wemm case TRY_AGAIN: 298c2aa98e2SPeter Wemm case -1: 299c2aa98e2SPeter Wemm /* couldn't connect to the name server */ 300c2aa98e2SPeter Wemm if (fallbackMX != NULL) 301c2aa98e2SPeter Wemm { 302c2aa98e2SPeter Wemm /* name server is hosed -- push to fallback */ 30340266059SGregory Neil Shapiro return fallbackmxrr(nmx, prefs, mxhosts); 304c2aa98e2SPeter Wemm } 305c2aa98e2SPeter Wemm /* it might come up later; better queue it up */ 306c2aa98e2SPeter Wemm *rcode = EX_TEMPFAIL; 307c2aa98e2SPeter Wemm break; 308c2aa98e2SPeter Wemm 309c2aa98e2SPeter Wemm default: 31040266059SGregory Neil Shapiro syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)", 311c2aa98e2SPeter Wemm host, h_errno); 312c2aa98e2SPeter Wemm *rcode = EX_OSERR; 313c2aa98e2SPeter Wemm break; 314c2aa98e2SPeter Wemm } 315c2aa98e2SPeter Wemm 316c2aa98e2SPeter Wemm /* irreconcilable differences */ 31706f25ae9SGregory Neil Shapiro return -1; 318c2aa98e2SPeter Wemm } 319c2aa98e2SPeter Wemm 320c2aa98e2SPeter Wemm /* avoid problems after truncation in tcp packets */ 321c2aa98e2SPeter Wemm if (n > sizeof(answer)) 322c2aa98e2SPeter Wemm n = sizeof(answer); 323c2aa98e2SPeter Wemm 324c2aa98e2SPeter Wemm /* find first satisfactory answer */ 325c2aa98e2SPeter Wemm hp = (HEADER *)&answer; 32640266059SGregory Neil Shapiro cp = (unsigned char *)&answer + HFIXEDSZ; 32740266059SGregory Neil Shapiro eom = (unsigned char *)&answer + n; 32840266059SGregory Neil Shapiro for (qdcount = ntohs((unsigned short) hp->qdcount); 32906f25ae9SGregory Neil Shapiro qdcount--; 33006f25ae9SGregory Neil Shapiro cp += n + QFIXEDSZ) 33106f25ae9SGregory Neil Shapiro { 332c2aa98e2SPeter Wemm if ((n = dn_skipname(cp, eom)) < 0) 333c2aa98e2SPeter Wemm goto punt; 33406f25ae9SGregory Neil Shapiro } 33540266059SGregory Neil Shapiro 33640266059SGregory Neil Shapiro /* NOTE: see definition of MXHostBuf! */ 337c2aa98e2SPeter Wemm buflen = sizeof(MXHostBuf) - 1; 33840266059SGregory Neil Shapiro SM_ASSERT(buflen > 0); 339c2aa98e2SPeter Wemm bp = MXHostBuf; 34040266059SGregory Neil Shapiro ancount = ntohs((unsigned short) hp->ancount); 34140266059SGregory Neil Shapiro 34240266059SGregory Neil Shapiro /* See RFC 1035 for layout of RRs. */ 34340266059SGregory Neil Shapiro /* XXX leave room for FallBackMX ? */ 344c2aa98e2SPeter Wemm while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1) 345c2aa98e2SPeter Wemm { 34640266059SGregory Neil Shapiro if ((n = dn_expand((unsigned char *)&answer, eom, cp, 34740266059SGregory Neil Shapiro (RES_UNC_T) bp, buflen)) < 0) 348c2aa98e2SPeter Wemm break; 349c2aa98e2SPeter Wemm cp += n; 350c2aa98e2SPeter Wemm GETSHORT(type, cp); 35140266059SGregory Neil Shapiro cp += INT16SZ; /* skip over class */ 35240266059SGregory Neil Shapiro GETLONG(ttl, cp); 35340266059SGregory Neil Shapiro GETSHORT(n, cp); /* rdlength */ 354c2aa98e2SPeter Wemm if (type != T_MX) 355c2aa98e2SPeter Wemm { 356c2aa98e2SPeter Wemm if (tTd(8, 8) || _res.options & RES_DEBUG) 35740266059SGregory Neil Shapiro sm_dprintf("unexpected answer type %d, size %d\n", 358c2aa98e2SPeter Wemm type, n); 359c2aa98e2SPeter Wemm cp += n; 360c2aa98e2SPeter Wemm continue; 361c2aa98e2SPeter Wemm } 362c2aa98e2SPeter Wemm GETSHORT(pref, cp); 36340266059SGregory Neil Shapiro if ((n = dn_expand((unsigned char *)&answer, eom, cp, 364c2aa98e2SPeter Wemm (RES_UNC_T) bp, buflen)) < 0) 365c2aa98e2SPeter Wemm break; 366c2aa98e2SPeter Wemm cp += n; 36740266059SGregory Neil Shapiro n = strlen(bp); 36840266059SGregory Neil Shapiro # if 0 36940266059SGregory Neil Shapiro /* Can this happen? */ 37040266059SGregory Neil Shapiro if (n == 0) 37140266059SGregory Neil Shapiro { 37240266059SGregory Neil Shapiro if (LogLevel > 4) 37340266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 37440266059SGregory Neil Shapiro "MX records for %s contain empty string", 37540266059SGregory Neil Shapiro host); 37640266059SGregory Neil Shapiro continue; 37740266059SGregory Neil Shapiro } 37840266059SGregory Neil Shapiro # endif /* 0 */ 379c2aa98e2SPeter Wemm if (wordinclass(bp, 'w')) 380c2aa98e2SPeter Wemm { 381c2aa98e2SPeter Wemm if (tTd(8, 3)) 38240266059SGregory Neil Shapiro sm_dprintf("found localhost (%s) in MX list, pref=%d\n", 383c2aa98e2SPeter Wemm bp, pref); 384c2aa98e2SPeter Wemm if (droplocalhost) 385c2aa98e2SPeter Wemm { 386c2aa98e2SPeter Wemm if (!seenlocal || pref < localpref) 387c2aa98e2SPeter Wemm localpref = pref; 38840266059SGregory Neil Shapiro seenlocal = true; 389c2aa98e2SPeter Wemm continue; 390c2aa98e2SPeter Wemm } 391c2aa98e2SPeter Wemm weight[nmx] = 0; 392c2aa98e2SPeter Wemm } 393c2aa98e2SPeter Wemm else 394c2aa98e2SPeter Wemm weight[nmx] = mxrand(bp); 39506f25ae9SGregory Neil Shapiro prefs[nmx] = pref; 396c2aa98e2SPeter Wemm mxhosts[nmx++] = bp; 397c2aa98e2SPeter Wemm bp += n; 398c2aa98e2SPeter Wemm if (bp[-1] != '.') 399c2aa98e2SPeter Wemm { 400c2aa98e2SPeter Wemm *bp++ = '.'; 401c2aa98e2SPeter Wemm n++; 402c2aa98e2SPeter Wemm } 403c2aa98e2SPeter Wemm *bp++ = '\0'; 40440266059SGregory Neil Shapiro if (buflen < n + 1) 40540266059SGregory Neil Shapiro { 40640266059SGregory Neil Shapiro /* don't want to wrap buflen */ 40740266059SGregory Neil Shapiro break; 40840266059SGregory Neil Shapiro } 409c2aa98e2SPeter Wemm buflen -= n + 1; 410c2aa98e2SPeter Wemm } 411c2aa98e2SPeter Wemm 41240266059SGregory Neil Shapiro /* return only one TTL entry, that should be sufficient */ 41340266059SGregory Neil Shapiro if (ttl > 0 && pttl != NULL) 41440266059SGregory Neil Shapiro *pttl = ttl; 41540266059SGregory Neil Shapiro 416c2aa98e2SPeter Wemm /* sort the records */ 417c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 418c2aa98e2SPeter Wemm { 419c2aa98e2SPeter Wemm for (j = i + 1; j < nmx; j++) 420c2aa98e2SPeter Wemm { 42106f25ae9SGregory Neil Shapiro if (prefs[i] > prefs[j] || 42206f25ae9SGregory Neil Shapiro (prefs[i] == prefs[j] && weight[i] > weight[j])) 423c2aa98e2SPeter Wemm { 424c2aa98e2SPeter Wemm register int temp; 425c2aa98e2SPeter Wemm register char *temp1; 426c2aa98e2SPeter Wemm 42706f25ae9SGregory Neil Shapiro temp = prefs[i]; 42806f25ae9SGregory Neil Shapiro prefs[i] = prefs[j]; 42906f25ae9SGregory Neil Shapiro prefs[j] = temp; 430c2aa98e2SPeter Wemm temp1 = mxhosts[i]; 431c2aa98e2SPeter Wemm mxhosts[i] = mxhosts[j]; 432c2aa98e2SPeter Wemm mxhosts[j] = temp1; 433c2aa98e2SPeter Wemm temp = weight[i]; 434c2aa98e2SPeter Wemm weight[i] = weight[j]; 435c2aa98e2SPeter Wemm weight[j] = temp; 436c2aa98e2SPeter Wemm } 437c2aa98e2SPeter Wemm } 43806f25ae9SGregory Neil Shapiro if (seenlocal && prefs[i] >= localpref) 439c2aa98e2SPeter Wemm { 440c2aa98e2SPeter Wemm /* truncate higher preference part of list */ 441c2aa98e2SPeter Wemm nmx = i; 442c2aa98e2SPeter Wemm } 443c2aa98e2SPeter Wemm } 444c2aa98e2SPeter Wemm 445c2aa98e2SPeter Wemm /* delete duplicates from list (yes, some bozos have duplicates) */ 446c2aa98e2SPeter Wemm for (i = 0; i < nmx - 1; ) 447c2aa98e2SPeter Wemm { 44840266059SGregory Neil Shapiro if (sm_strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0) 449c2aa98e2SPeter Wemm i++; 450c2aa98e2SPeter Wemm else 451c2aa98e2SPeter Wemm { 452c2aa98e2SPeter Wemm /* compress out duplicate */ 453c2aa98e2SPeter Wemm for (j = i + 1; j < nmx; j++) 45406f25ae9SGregory Neil Shapiro { 455c2aa98e2SPeter Wemm mxhosts[j] = mxhosts[j + 1]; 45606f25ae9SGregory Neil Shapiro prefs[j] = prefs[j + 1]; 45706f25ae9SGregory Neil Shapiro } 458c2aa98e2SPeter Wemm nmx--; 459c2aa98e2SPeter Wemm } 460c2aa98e2SPeter Wemm } 461c2aa98e2SPeter Wemm 462c2aa98e2SPeter Wemm if (nmx == 0) 463c2aa98e2SPeter Wemm { 464c2aa98e2SPeter Wemm punt: 46506f25ae9SGregory Neil Shapiro if (seenlocal) 466c2aa98e2SPeter Wemm { 46706f25ae9SGregory Neil Shapiro struct hostent *h = NULL; 46806f25ae9SGregory Neil Shapiro 469c2aa98e2SPeter Wemm /* 470c2aa98e2SPeter Wemm ** If we have deleted all MX entries, this is 471c2aa98e2SPeter Wemm ** an error -- we should NEVER send to a host that 472c2aa98e2SPeter Wemm ** has an MX, and this should have been caught 473c2aa98e2SPeter Wemm ** earlier in the config file. 474c2aa98e2SPeter Wemm ** 475c2aa98e2SPeter Wemm ** Some sites prefer to go ahead and try the 476c2aa98e2SPeter Wemm ** A record anyway; that case is handled by 477c2aa98e2SPeter Wemm ** setting TryNullMXList. I believe this is a 478c2aa98e2SPeter Wemm ** bad idea, but it's up to you.... 479c2aa98e2SPeter Wemm */ 480c2aa98e2SPeter Wemm 48106f25ae9SGregory Neil Shapiro if (TryNullMXList) 48206f25ae9SGregory Neil Shapiro { 483602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 48406f25ae9SGregory Neil Shapiro errno = 0; 48506f25ae9SGregory Neil Shapiro h = sm_gethostbyname(host, AF_INET); 48606f25ae9SGregory Neil Shapiro if (h == NULL) 48706f25ae9SGregory Neil Shapiro { 48806f25ae9SGregory Neil Shapiro if (errno == ETIMEDOUT || 48906f25ae9SGregory Neil Shapiro h_errno == TRY_AGAIN || 49006f25ae9SGregory Neil Shapiro (errno == ECONNREFUSED && 49106f25ae9SGregory Neil Shapiro UseNameServer)) 49206f25ae9SGregory Neil Shapiro { 49306f25ae9SGregory Neil Shapiro *rcode = EX_TEMPFAIL; 49406f25ae9SGregory Neil Shapiro return -1; 49506f25ae9SGregory Neil Shapiro } 49606f25ae9SGregory Neil Shapiro # if NETINET6 497602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 49806f25ae9SGregory Neil Shapiro errno = 0; 49906f25ae9SGregory Neil Shapiro h = sm_gethostbyname(host, AF_INET6); 50006f25ae9SGregory Neil Shapiro if (h == NULL && 50106f25ae9SGregory Neil Shapiro (errno == ETIMEDOUT || 50206f25ae9SGregory Neil Shapiro h_errno == TRY_AGAIN || 50306f25ae9SGregory Neil Shapiro (errno == ECONNREFUSED && 50406f25ae9SGregory Neil Shapiro UseNameServer))) 50506f25ae9SGregory Neil Shapiro { 50606f25ae9SGregory Neil Shapiro *rcode = EX_TEMPFAIL; 50706f25ae9SGregory Neil Shapiro return -1; 50806f25ae9SGregory Neil Shapiro } 50906f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 51006f25ae9SGregory Neil Shapiro } 51106f25ae9SGregory Neil Shapiro } 51206f25ae9SGregory Neil Shapiro 51306f25ae9SGregory Neil Shapiro if (h == NULL) 51406f25ae9SGregory Neil Shapiro { 515c2aa98e2SPeter Wemm *rcode = EX_CONFIG; 516c2aa98e2SPeter Wemm syserr("MX list for %s points back to %s", 517c2aa98e2SPeter Wemm host, MyHostName); 518c2aa98e2SPeter Wemm return -1; 519c2aa98e2SPeter Wemm } 52040266059SGregory Neil Shapiro # if NETINET6 521193538b7SGregory Neil Shapiro freehostent(h); 522193538b7SGregory Neil Shapiro hp = NULL; 52340266059SGregory Neil Shapiro # endif /* NETINET6 */ 52406f25ae9SGregory Neil Shapiro } 52540266059SGregory Neil Shapiro if (strlen(host) >= sizeof MXHostBuf) 526c2aa98e2SPeter Wemm { 527c2aa98e2SPeter Wemm *rcode = EX_CONFIG; 528c2aa98e2SPeter Wemm syserr("Host name %s too long", 529c2aa98e2SPeter Wemm shortenstring(host, MAXSHORTSTR)); 530c2aa98e2SPeter Wemm return -1; 531c2aa98e2SPeter Wemm } 53240266059SGregory Neil Shapiro (void) sm_strlcpy(MXHostBuf, host, sizeof MXHostBuf); 533c2aa98e2SPeter Wemm mxhosts[0] = MXHostBuf; 53406f25ae9SGregory Neil Shapiro prefs[0] = 0; 535c2aa98e2SPeter Wemm if (host[0] == '[') 536c2aa98e2SPeter Wemm { 537c2aa98e2SPeter Wemm register char *p; 53806f25ae9SGregory Neil Shapiro # if NETINET6 53906f25ae9SGregory Neil Shapiro struct sockaddr_in6 tmp6; 54006f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 541c2aa98e2SPeter Wemm 542c2aa98e2SPeter Wemm /* this may be an MX suppression-style address */ 543c2aa98e2SPeter Wemm p = strchr(MXHostBuf, ']'); 544c2aa98e2SPeter Wemm if (p != NULL) 545c2aa98e2SPeter Wemm { 546c2aa98e2SPeter Wemm *p = '\0'; 54706f25ae9SGregory Neil Shapiro 548c2aa98e2SPeter Wemm if (inet_addr(&MXHostBuf[1]) != INADDR_NONE) 549c2aa98e2SPeter Wemm { 550c2aa98e2SPeter Wemm nmx++; 551c2aa98e2SPeter Wemm *p = ']'; 552c2aa98e2SPeter Wemm } 55306f25ae9SGregory Neil Shapiro # if NETINET6 55440266059SGregory Neil Shapiro else if (anynet_pton(AF_INET6, &MXHostBuf[1], 55506f25ae9SGregory Neil Shapiro &tmp6.sin6_addr) == 1) 55606f25ae9SGregory Neil Shapiro { 55706f25ae9SGregory Neil Shapiro nmx++; 55806f25ae9SGregory Neil Shapiro *p = ']'; 55906f25ae9SGregory Neil Shapiro } 56006f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 561c2aa98e2SPeter Wemm else 562c2aa98e2SPeter Wemm { 56340266059SGregory Neil Shapiro trycanon = true; 564c2aa98e2SPeter Wemm mxhosts[0]++; 565c2aa98e2SPeter Wemm } 566c2aa98e2SPeter Wemm } 567c2aa98e2SPeter Wemm } 568c2aa98e2SPeter Wemm if (trycanon && 56940266059SGregory Neil Shapiro getcanonname(mxhosts[0], sizeof MXHostBuf - 2, false, pttl)) 570c2aa98e2SPeter Wemm { 57140266059SGregory Neil Shapiro /* XXX MXHostBuf == "" ? is that possible? */ 572c2aa98e2SPeter Wemm bp = &MXHostBuf[strlen(MXHostBuf)]; 573c2aa98e2SPeter Wemm if (bp[-1] != '.') 574c2aa98e2SPeter Wemm { 575c2aa98e2SPeter Wemm *bp++ = '.'; 576c2aa98e2SPeter Wemm *bp = '\0'; 577c2aa98e2SPeter Wemm } 578c2aa98e2SPeter Wemm nmx = 1; 579c2aa98e2SPeter Wemm } 580c2aa98e2SPeter Wemm } 581c2aa98e2SPeter Wemm 582c2aa98e2SPeter Wemm /* if we have a default lowest preference, include that */ 583c2aa98e2SPeter Wemm if (fallbackMX != NULL && !seenlocal) 58406f25ae9SGregory Neil Shapiro { 58540266059SGregory Neil Shapiro nmx = fallbackmxrr(nmx, prefs, mxhosts); 58606f25ae9SGregory Neil Shapiro } 58706f25ae9SGregory Neil Shapiro return nmx; 588c2aa98e2SPeter Wemm } 58940266059SGregory Neil Shapiro /* 590c2aa98e2SPeter Wemm ** MXRAND -- create a randomizer for equal MX preferences 591c2aa98e2SPeter Wemm ** 592c2aa98e2SPeter Wemm ** If two MX hosts have equal preferences we want to randomize 593c2aa98e2SPeter Wemm ** the selection. But in order for signatures to be the same, 594c2aa98e2SPeter Wemm ** we need to randomize the same way each time. This function 595c2aa98e2SPeter Wemm ** computes a pseudo-random hash function from the host name. 596c2aa98e2SPeter Wemm ** 597c2aa98e2SPeter Wemm ** Parameters: 598c2aa98e2SPeter Wemm ** host -- the name of the host. 599c2aa98e2SPeter Wemm ** 600c2aa98e2SPeter Wemm ** Returns: 601c2aa98e2SPeter Wemm ** A random but repeatable value based on the host name. 602c2aa98e2SPeter Wemm */ 603c2aa98e2SPeter Wemm 60406f25ae9SGregory Neil Shapiro static int 605c2aa98e2SPeter Wemm mxrand(host) 606c2aa98e2SPeter Wemm register char *host; 607c2aa98e2SPeter Wemm { 608c2aa98e2SPeter Wemm int hfunc; 609c2aa98e2SPeter Wemm static unsigned int seed; 610c2aa98e2SPeter Wemm 611c2aa98e2SPeter Wemm if (seed == 0) 612c2aa98e2SPeter Wemm { 613c2aa98e2SPeter Wemm seed = (int) curtime() & 0xffff; 614c2aa98e2SPeter Wemm if (seed == 0) 615c2aa98e2SPeter Wemm seed++; 616c2aa98e2SPeter Wemm } 617c2aa98e2SPeter Wemm 618c2aa98e2SPeter Wemm if (tTd(17, 9)) 61940266059SGregory Neil Shapiro sm_dprintf("mxrand(%s)", host); 620c2aa98e2SPeter Wemm 621c2aa98e2SPeter Wemm hfunc = seed; 622c2aa98e2SPeter Wemm while (*host != '\0') 623c2aa98e2SPeter Wemm { 624c2aa98e2SPeter Wemm int c = *host++; 625c2aa98e2SPeter Wemm 626c2aa98e2SPeter Wemm if (isascii(c) && isupper(c)) 627c2aa98e2SPeter Wemm c = tolower(c); 628c2aa98e2SPeter Wemm hfunc = ((hfunc << 1) ^ c) % 2003; 629c2aa98e2SPeter Wemm } 630c2aa98e2SPeter Wemm 631c2aa98e2SPeter Wemm hfunc &= 0xff; 632c2aa98e2SPeter Wemm hfunc++; 633c2aa98e2SPeter Wemm 634c2aa98e2SPeter Wemm if (tTd(17, 9)) 63540266059SGregory Neil Shapiro sm_dprintf(" = %d\n", hfunc); 636c2aa98e2SPeter Wemm return hfunc; 637c2aa98e2SPeter Wemm } 63840266059SGregory Neil Shapiro /* 639c2aa98e2SPeter Wemm ** BESTMX -- find the best MX for a name 640c2aa98e2SPeter Wemm ** 641c2aa98e2SPeter Wemm ** This is really a hack, but I don't see any obvious way 642c2aa98e2SPeter Wemm ** to generalize it at the moment. 643c2aa98e2SPeter Wemm */ 644c2aa98e2SPeter Wemm 645c2aa98e2SPeter Wemm /* ARGSUSED3 */ 646c2aa98e2SPeter Wemm char * 647c2aa98e2SPeter Wemm bestmx_map_lookup(map, name, av, statp) 648c2aa98e2SPeter Wemm MAP *map; 649c2aa98e2SPeter Wemm char *name; 650c2aa98e2SPeter Wemm char **av; 651c2aa98e2SPeter Wemm int *statp; 652c2aa98e2SPeter Wemm { 653c2aa98e2SPeter Wemm int nmx; 654c2aa98e2SPeter Wemm int saveopts = _res.options; 65540266059SGregory Neil Shapiro int i; 65640266059SGregory Neil Shapiro ssize_t len = 0; 65740266059SGregory Neil Shapiro char *result; 658c2aa98e2SPeter Wemm char *mxhosts[MAXMXHOSTS + 1]; 65940266059SGregory Neil Shapiro #if _FFR_BESTMX_BETTER_TRUNCATION 66040266059SGregory Neil Shapiro char *buf; 66140266059SGregory Neil Shapiro #else /* _FFR_BESTMX_BETTER_TRUNCATION */ 66240266059SGregory Neil Shapiro char *p; 663065a643dSPeter Wemm char buf[PSBUFSIZE / 2]; 66440266059SGregory Neil Shapiro #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 665c2aa98e2SPeter Wemm 666c2aa98e2SPeter Wemm _res.options &= ~(RES_DNSRCH|RES_DEFNAMES); 66740266059SGregory Neil Shapiro nmx = getmxrr(name, mxhosts, NULL, false, statp, true, NULL); 668c2aa98e2SPeter Wemm _res.options = saveopts; 669c2aa98e2SPeter Wemm if (nmx <= 0) 670c2aa98e2SPeter Wemm return NULL; 671c2aa98e2SPeter Wemm if (bitset(MF_MATCHONLY, map->map_mflags)) 672c2aa98e2SPeter Wemm return map_rewrite(map, name, strlen(name), NULL); 673c2aa98e2SPeter Wemm if ((map->map_coldelim == '\0') || (nmx == 1)) 674c2aa98e2SPeter Wemm return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av); 675c2aa98e2SPeter Wemm 676c2aa98e2SPeter Wemm /* 677c2aa98e2SPeter Wemm ** We were given a -z flag (return all MXs) and there are multiple 678c2aa98e2SPeter Wemm ** ones. We need to build them all into a list. 679c2aa98e2SPeter Wemm */ 68040266059SGregory Neil Shapiro 68140266059SGregory Neil Shapiro #if _FFR_BESTMX_BETTER_TRUNCATION 68240266059SGregory Neil Shapiro for (i = 0; i < nmx; i++) 68340266059SGregory Neil Shapiro { 68440266059SGregory Neil Shapiro if (strchr(mxhosts[i], map->map_coldelim) != NULL) 68540266059SGregory Neil Shapiro { 68640266059SGregory Neil Shapiro syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 68740266059SGregory Neil Shapiro mxhosts[i], map->map_coldelim); 68840266059SGregory Neil Shapiro return NULL; 68940266059SGregory Neil Shapiro } 69040266059SGregory Neil Shapiro len += strlen(mxhosts[i]) + 1; 69140266059SGregory Neil Shapiro if (len < 0) 69240266059SGregory Neil Shapiro { 69340266059SGregory Neil Shapiro len -= strlen(mxhosts[i]) + 1; 69440266059SGregory Neil Shapiro break; 69540266059SGregory Neil Shapiro } 69640266059SGregory Neil Shapiro } 69740266059SGregory Neil Shapiro buf = (char *) sm_malloc(len); 69840266059SGregory Neil Shapiro if (buf == NULL) 69940266059SGregory Neil Shapiro { 70040266059SGregory Neil Shapiro *statp = EX_UNAVAILABLE; 70140266059SGregory Neil Shapiro return NULL; 70240266059SGregory Neil Shapiro } 70340266059SGregory Neil Shapiro *buf = '\0'; 70440266059SGregory Neil Shapiro for (i = 0; i < nmx; i++) 70540266059SGregory Neil Shapiro { 70640266059SGregory Neil Shapiro int end; 70740266059SGregory Neil Shapiro 70840266059SGregory Neil Shapiro end = sm_strlcat(buf, mxhosts[i], len); 70940266059SGregory Neil Shapiro if (i != nmx && end + 1 < len) 71040266059SGregory Neil Shapiro { 71140266059SGregory Neil Shapiro buf[end] = map->map_coldelim; 71240266059SGregory Neil Shapiro buf[end + 1] = '\0'; 71340266059SGregory Neil Shapiro } 71440266059SGregory Neil Shapiro } 71540266059SGregory Neil Shapiro 71640266059SGregory Neil Shapiro /* Cleanly truncate for rulesets */ 71740266059SGregory Neil Shapiro truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim); 71840266059SGregory Neil Shapiro #else /* _FFR_BESTMX_BETTER_TRUNCATION */ 719c2aa98e2SPeter Wemm p = buf; 720c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 721c2aa98e2SPeter Wemm { 72240266059SGregory Neil Shapiro size_t slen; 723c2aa98e2SPeter Wemm 724c2aa98e2SPeter Wemm if (strchr(mxhosts[i], map->map_coldelim) != NULL) 725c2aa98e2SPeter Wemm { 726c2aa98e2SPeter Wemm syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 727c2aa98e2SPeter Wemm mxhosts[i], map->map_coldelim); 728c2aa98e2SPeter Wemm return NULL; 729c2aa98e2SPeter Wemm } 730c2aa98e2SPeter Wemm slen = strlen(mxhosts[i]); 731c2aa98e2SPeter Wemm if (len + slen + 2 > sizeof buf) 732c2aa98e2SPeter Wemm break; 733c2aa98e2SPeter Wemm if (i > 0) 734c2aa98e2SPeter Wemm { 735c2aa98e2SPeter Wemm *p++ = map->map_coldelim; 736c2aa98e2SPeter Wemm len++; 737c2aa98e2SPeter Wemm } 73840266059SGregory Neil Shapiro (void) sm_strlcpy(p, mxhosts[i], sizeof buf - len); 739c2aa98e2SPeter Wemm p += slen; 740c2aa98e2SPeter Wemm len += slen; 741c2aa98e2SPeter Wemm } 74240266059SGregory Neil Shapiro #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 74340266059SGregory Neil Shapiro 74440266059SGregory Neil Shapiro result = map_rewrite(map, buf, len, av); 74540266059SGregory Neil Shapiro #if _FFR_BESTMX_BETTER_TRUNCATION 74640266059SGregory Neil Shapiro sm_free(buf); 74740266059SGregory Neil Shapiro #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 74840266059SGregory Neil Shapiro return result; 749c2aa98e2SPeter Wemm } 75040266059SGregory Neil Shapiro /* 751c2aa98e2SPeter Wemm ** DNS_GETCANONNAME -- get the canonical name for named host using DNS 752c2aa98e2SPeter Wemm ** 753c2aa98e2SPeter Wemm ** This algorithm tries to be smart about wildcard MX records. 754c2aa98e2SPeter Wemm ** This is hard to do because DNS doesn't tell is if we matched 755c2aa98e2SPeter Wemm ** against a wildcard or a specific MX. 756c2aa98e2SPeter Wemm ** 757c2aa98e2SPeter Wemm ** We always prefer A & CNAME records, since these are presumed 758c2aa98e2SPeter Wemm ** to be specific. 759c2aa98e2SPeter Wemm ** 760c2aa98e2SPeter Wemm ** If we match an MX in one pass and lose it in the next, we use 761c2aa98e2SPeter Wemm ** the old one. For example, consider an MX matching *.FOO.BAR.COM. 762c2aa98e2SPeter Wemm ** A hostname bletch.foo.bar.com will match against this MX, but 763c2aa98e2SPeter Wemm ** will stop matching when we try bletch.bar.com -- so we know 764c2aa98e2SPeter Wemm ** that bletch.foo.bar.com must have been right. This fails if 765c2aa98e2SPeter Wemm ** there was also an MX record matching *.BAR.COM, but there are 766c2aa98e2SPeter Wemm ** some things that just can't be fixed. 767c2aa98e2SPeter Wemm ** 768c2aa98e2SPeter Wemm ** Parameters: 769c2aa98e2SPeter Wemm ** host -- a buffer containing the name of the host. 770c2aa98e2SPeter Wemm ** This is a value-result parameter. 771c2aa98e2SPeter Wemm ** hbsize -- the size of the host buffer. 772c2aa98e2SPeter Wemm ** trymx -- if set, try MX records as well as A and CNAME. 773c2aa98e2SPeter Wemm ** statp -- pointer to place to store status. 77440266059SGregory Neil Shapiro ** pttl -- pointer to return TTL (can be NULL). 775c2aa98e2SPeter Wemm ** 776c2aa98e2SPeter Wemm ** Returns: 77740266059SGregory Neil Shapiro ** true -- if the host matched. 77840266059SGregory Neil Shapiro ** false -- otherwise. 779c2aa98e2SPeter Wemm */ 780c2aa98e2SPeter Wemm 78140266059SGregory Neil Shapiro # if NETINET6 78240266059SGregory Neil Shapiro # define SM_T_INITIAL T_AAAA 78340266059SGregory Neil Shapiro # else /* NETINET6 */ 78440266059SGregory Neil Shapiro # define SM_T_INITIAL T_A 78540266059SGregory Neil Shapiro # endif /* NETINET6 */ 78640266059SGregory Neil Shapiro 787c2aa98e2SPeter Wemm bool 78840266059SGregory Neil Shapiro dns_getcanonname(host, hbsize, trymx, statp, pttl) 789c2aa98e2SPeter Wemm char *host; 790c2aa98e2SPeter Wemm int hbsize; 791c2aa98e2SPeter Wemm bool trymx; 792c2aa98e2SPeter Wemm int *statp; 79340266059SGregory Neil Shapiro int *pttl; 794c2aa98e2SPeter Wemm { 79540266059SGregory Neil Shapiro register unsigned char *eom, *ap; 796c2aa98e2SPeter Wemm register char *cp; 797c2aa98e2SPeter Wemm register int n; 798c2aa98e2SPeter Wemm HEADER *hp; 799c2aa98e2SPeter Wemm querybuf answer; 800c2aa98e2SPeter Wemm int ancount, qdcount; 801c2aa98e2SPeter Wemm int ret; 802c2aa98e2SPeter Wemm char **domain; 803c2aa98e2SPeter Wemm int type; 80440266059SGregory Neil Shapiro int ttl = 0; 805c2aa98e2SPeter Wemm char **dp; 806c2aa98e2SPeter Wemm char *mxmatch; 807c2aa98e2SPeter Wemm bool amatch; 80840266059SGregory Neil Shapiro bool gotmx = false; 809c2aa98e2SPeter Wemm int qtype; 810c2aa98e2SPeter Wemm int loopcnt; 811c2aa98e2SPeter Wemm char *xp; 81240266059SGregory Neil Shapiro char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)]; 813c2aa98e2SPeter Wemm char *searchlist[MAXDNSRCH+2]; 814c2aa98e2SPeter Wemm 815c2aa98e2SPeter Wemm if (tTd(8, 2)) 81640266059SGregory Neil Shapiro sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx); 817c2aa98e2SPeter Wemm 818c2aa98e2SPeter Wemm if ((_res.options & RES_INIT) == 0 && res_init() == -1) 819c2aa98e2SPeter Wemm { 820c2aa98e2SPeter Wemm *statp = EX_UNAVAILABLE; 82140266059SGregory Neil Shapiro return false; 822c2aa98e2SPeter Wemm } 823c2aa98e2SPeter Wemm 824193538b7SGregory Neil Shapiro *statp = EX_OK; 825193538b7SGregory Neil Shapiro 826c2aa98e2SPeter Wemm /* 827c2aa98e2SPeter Wemm ** Initialize domain search list. If there is at least one 828c2aa98e2SPeter Wemm ** dot in the name, search the unmodified name first so we 829c2aa98e2SPeter Wemm ** find "vse.CS" in Czechoslovakia instead of in the local 83006f25ae9SGregory Neil Shapiro ** domain (e.g., vse.CS.Berkeley.EDU). Note that there is no 83106f25ae9SGregory Neil Shapiro ** longer a country named Czechoslovakia but this type of problem 83206f25ae9SGregory Neil Shapiro ** is still present. 833c2aa98e2SPeter Wemm ** 834c2aa98e2SPeter Wemm ** Older versions of the resolver could create this 835c2aa98e2SPeter Wemm ** list by tearing apart the host name. 836c2aa98e2SPeter Wemm */ 837c2aa98e2SPeter Wemm 838c2aa98e2SPeter Wemm loopcnt = 0; 839c2aa98e2SPeter Wemm cnameloop: 840c2aa98e2SPeter Wemm /* Check for dots in the name */ 841c2aa98e2SPeter Wemm for (cp = host, n = 0; *cp != '\0'; cp++) 842c2aa98e2SPeter Wemm if (*cp == '.') 843c2aa98e2SPeter Wemm n++; 844c2aa98e2SPeter Wemm 845c2aa98e2SPeter Wemm /* 846c2aa98e2SPeter Wemm ** If this is a simple name, determine whether it matches an 847c2aa98e2SPeter Wemm ** alias in the file defined by the environment variable HOSTALIASES. 848c2aa98e2SPeter Wemm */ 84940266059SGregory Neil Shapiro 850c2aa98e2SPeter Wemm if (n == 0 && (xp = gethostalias(host)) != NULL) 851c2aa98e2SPeter Wemm { 852c2aa98e2SPeter Wemm if (loopcnt++ > MAXCNAMEDEPTH) 853c2aa98e2SPeter Wemm { 854c2aa98e2SPeter Wemm syserr("loop in ${HOSTALIASES} file"); 855c2aa98e2SPeter Wemm } 856c2aa98e2SPeter Wemm else 857c2aa98e2SPeter Wemm { 85840266059SGregory Neil Shapiro (void) sm_strlcpy(host, xp, hbsize); 859c2aa98e2SPeter Wemm goto cnameloop; 860c2aa98e2SPeter Wemm } 861c2aa98e2SPeter Wemm } 862c2aa98e2SPeter Wemm 863c2aa98e2SPeter Wemm /* 864c2aa98e2SPeter Wemm ** Build the search list. 865c2aa98e2SPeter Wemm ** If there is at least one dot in name, start with a null 866c2aa98e2SPeter Wemm ** domain to search the unmodified name first. 867c2aa98e2SPeter Wemm ** If name does not end with a dot and search up local domain 868c2aa98e2SPeter Wemm ** tree desired, append each local domain component to the 869c2aa98e2SPeter Wemm ** search list; if name contains no dots and default domain 870c2aa98e2SPeter Wemm ** name is desired, append default domain name to search list; 871c2aa98e2SPeter Wemm ** else if name ends in a dot, remove that dot. 872c2aa98e2SPeter Wemm */ 873c2aa98e2SPeter Wemm 874c2aa98e2SPeter Wemm dp = searchlist; 875c2aa98e2SPeter Wemm if (n > 0) 876c2aa98e2SPeter Wemm *dp++ = ""; 877c2aa98e2SPeter Wemm if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options)) 878c2aa98e2SPeter Wemm { 87906f25ae9SGregory Neil Shapiro /* make sure there are less than MAXDNSRCH domains */ 88006f25ae9SGregory Neil Shapiro for (domain = RES_DNSRCH_VARIABLE, ret = 0; 88106f25ae9SGregory Neil Shapiro *domain != NULL && ret < MAXDNSRCH; 88206f25ae9SGregory Neil Shapiro ret++) 883c2aa98e2SPeter Wemm *dp++ = *domain++; 884c2aa98e2SPeter Wemm } 885c2aa98e2SPeter Wemm else if (n == 0 && bitset(RES_DEFNAMES, _res.options)) 886c2aa98e2SPeter Wemm { 887c2aa98e2SPeter Wemm *dp++ = _res.defdname; 888c2aa98e2SPeter Wemm } 889c2aa98e2SPeter Wemm else if (*cp == '.') 890c2aa98e2SPeter Wemm { 891c2aa98e2SPeter Wemm *cp = '\0'; 892c2aa98e2SPeter Wemm } 893c2aa98e2SPeter Wemm *dp = NULL; 894c2aa98e2SPeter Wemm 895c2aa98e2SPeter Wemm /* 896c2aa98e2SPeter Wemm ** Now loop through the search list, appending each domain in turn 897c2aa98e2SPeter Wemm ** name and searching for a match. 898c2aa98e2SPeter Wemm */ 899c2aa98e2SPeter Wemm 900c2aa98e2SPeter Wemm mxmatch = NULL; 90140266059SGregory Neil Shapiro qtype = SM_T_INITIAL; 902c2aa98e2SPeter Wemm 903c2aa98e2SPeter Wemm for (dp = searchlist; *dp != NULL; ) 904c2aa98e2SPeter Wemm { 90540266059SGregory Neil Shapiro if (qtype == SM_T_INITIAL) 90640266059SGregory Neil Shapiro gotmx = false; 907c2aa98e2SPeter Wemm if (tTd(8, 5)) 90840266059SGregory Neil Shapiro sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n", 909c2aa98e2SPeter Wemm host, *dp, 91006f25ae9SGregory Neil Shapiro # if NETINET6 91106f25ae9SGregory Neil Shapiro qtype == T_AAAA ? "AAAA" : 91206f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 91306f25ae9SGregory Neil Shapiro qtype == T_A ? "A" : 91406f25ae9SGregory Neil Shapiro qtype == T_MX ? "MX" : 91506f25ae9SGregory Neil Shapiro "???"); 916193538b7SGregory Neil Shapiro errno = 0; 917c2aa98e2SPeter Wemm ret = res_querydomain(host, *dp, C_IN, qtype, 918c2aa98e2SPeter Wemm answer.qb2, sizeof(answer.qb2)); 919c2aa98e2SPeter Wemm if (ret <= 0) 920c2aa98e2SPeter Wemm { 92140266059SGregory Neil Shapiro int save_errno = errno; 922c2aa98e2SPeter Wemm 92340266059SGregory Neil Shapiro if (tTd(8, 7)) 92440266059SGregory Neil Shapiro sm_dprintf("\tNO: errno=%d, h_errno=%d\n", 92540266059SGregory Neil Shapiro save_errno, h_errno); 92640266059SGregory Neil Shapiro 92740266059SGregory Neil Shapiro if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN) 928c2aa98e2SPeter Wemm { 929193538b7SGregory Neil Shapiro /* 93040266059SGregory Neil Shapiro ** the name server seems to be down or broken. 931193538b7SGregory Neil Shapiro */ 932193538b7SGregory Neil Shapiro 933602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(TRY_AGAIN); 934c2aa98e2SPeter Wemm *statp = EX_TEMPFAIL; 93506f25ae9SGregory Neil Shapiro 936602a2b1bSGregory Neil Shapiro if (WorkAroundBrokenAAAA) 937602a2b1bSGregory Neil Shapiro { 938193538b7SGregory Neil Shapiro /* 939193538b7SGregory Neil Shapiro ** Only return if not TRY_AGAIN as an 940193538b7SGregory Neil Shapiro ** attempt with a different qtype may 941193538b7SGregory Neil Shapiro ** succeed (res_querydomain() calls 942193538b7SGregory Neil Shapiro ** res_query() calls res_send() which 943193538b7SGregory Neil Shapiro ** sets errno to ETIMEDOUT if the 944193538b7SGregory Neil Shapiro ** nameservers could be contacted but 945193538b7SGregory Neil Shapiro ** didn't give an answer). 946193538b7SGregory Neil Shapiro */ 947193538b7SGregory Neil Shapiro 94840266059SGregory Neil Shapiro if (save_errno != ETIMEDOUT) 94940266059SGregory Neil Shapiro return false; 950602a2b1bSGregory Neil Shapiro } 95140266059SGregory Neil Shapiro else 95240266059SGregory Neil Shapiro return false; 953c2aa98e2SPeter Wemm } 954c2aa98e2SPeter Wemm 955c2aa98e2SPeter Wemm if (h_errno != HOST_NOT_FOUND) 956c2aa98e2SPeter Wemm { 957c2aa98e2SPeter Wemm /* might have another type of interest */ 95806f25ae9SGregory Neil Shapiro # if NETINET6 95940266059SGregory Neil Shapiro if (qtype == T_AAAA) 96006f25ae9SGregory Neil Shapiro { 961c2aa98e2SPeter Wemm qtype = T_A; 962c2aa98e2SPeter Wemm continue; 963c2aa98e2SPeter Wemm } 96440266059SGregory Neil Shapiro else 96506f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 96640266059SGregory Neil Shapiro if (qtype == T_A && !gotmx && 96706f25ae9SGregory Neil Shapiro (trymx || **dp == '\0')) 968c2aa98e2SPeter Wemm { 969c2aa98e2SPeter Wemm qtype = T_MX; 970c2aa98e2SPeter Wemm continue; 971c2aa98e2SPeter Wemm } 972c2aa98e2SPeter Wemm } 973c2aa98e2SPeter Wemm 974c2aa98e2SPeter Wemm /* definite no -- try the next domain */ 975c2aa98e2SPeter Wemm dp++; 97640266059SGregory Neil Shapiro qtype = SM_T_INITIAL; 977c2aa98e2SPeter Wemm continue; 978c2aa98e2SPeter Wemm } 979c2aa98e2SPeter Wemm else if (tTd(8, 7)) 98040266059SGregory Neil Shapiro sm_dprintf("\tYES\n"); 981c2aa98e2SPeter Wemm 982c2aa98e2SPeter Wemm /* avoid problems after truncation in tcp packets */ 983c2aa98e2SPeter Wemm if (ret > sizeof(answer)) 984c2aa98e2SPeter Wemm ret = sizeof(answer); 98540266059SGregory Neil Shapiro if (ret < 0) 98640266059SGregory Neil Shapiro { 98740266059SGregory Neil Shapiro *statp = EX_SOFTWARE; 98840266059SGregory Neil Shapiro return false; 98940266059SGregory Neil Shapiro } 990c2aa98e2SPeter Wemm 991c2aa98e2SPeter Wemm /* 992c2aa98e2SPeter Wemm ** Appear to have a match. Confirm it by searching for A or 993c2aa98e2SPeter Wemm ** CNAME records. If we don't have a local domain 994c2aa98e2SPeter Wemm ** wild card MX record, we will accept MX as well. 995c2aa98e2SPeter Wemm */ 996c2aa98e2SPeter Wemm 997c2aa98e2SPeter Wemm hp = (HEADER *) &answer; 99840266059SGregory Neil Shapiro ap = (unsigned char *) &answer + HFIXEDSZ; 99940266059SGregory Neil Shapiro eom = (unsigned char *) &answer + ret; 1000c2aa98e2SPeter Wemm 1001c2aa98e2SPeter Wemm /* skip question part of response -- we know what we asked */ 100240266059SGregory Neil Shapiro for (qdcount = ntohs((unsigned short) hp->qdcount); 100306f25ae9SGregory Neil Shapiro qdcount--; 100406f25ae9SGregory Neil Shapiro ap += ret + QFIXEDSZ) 1005c2aa98e2SPeter Wemm { 1006c2aa98e2SPeter Wemm if ((ret = dn_skipname(ap, eom)) < 0) 1007c2aa98e2SPeter Wemm { 1008c2aa98e2SPeter Wemm if (tTd(8, 20)) 100940266059SGregory Neil Shapiro sm_dprintf("qdcount failure (%d)\n", 101040266059SGregory Neil Shapiro ntohs((unsigned short) hp->qdcount)); 1011c2aa98e2SPeter Wemm *statp = EX_SOFTWARE; 101240266059SGregory Neil Shapiro return false; /* ???XXX??? */ 1013c2aa98e2SPeter Wemm } 1014c2aa98e2SPeter Wemm } 1015c2aa98e2SPeter Wemm 101640266059SGregory Neil Shapiro amatch = false; 101740266059SGregory Neil Shapiro for (ancount = ntohs((unsigned short) hp->ancount); 101806f25ae9SGregory Neil Shapiro --ancount >= 0 && ap < eom; 1019c2aa98e2SPeter Wemm ap += n) 1020c2aa98e2SPeter Wemm { 102140266059SGregory Neil Shapiro n = dn_expand((unsigned char *) &answer, eom, ap, 1022c2aa98e2SPeter Wemm (RES_UNC_T) nbuf, sizeof nbuf); 1023c2aa98e2SPeter Wemm if (n < 0) 1024c2aa98e2SPeter Wemm break; 1025c2aa98e2SPeter Wemm ap += n; 1026c2aa98e2SPeter Wemm GETSHORT(type, ap); 102740266059SGregory Neil Shapiro ap += INT16SZ; /* skip over class */ 102840266059SGregory Neil Shapiro GETLONG(ttl, ap); 102940266059SGregory Neil Shapiro GETSHORT(n, ap); /* rdlength */ 1030c2aa98e2SPeter Wemm switch (type) 1031c2aa98e2SPeter Wemm { 1032c2aa98e2SPeter Wemm case T_MX: 103340266059SGregory Neil Shapiro gotmx = true; 1034c2aa98e2SPeter Wemm if (**dp != '\0' && HasWildcardMX) 1035c2aa98e2SPeter Wemm { 1036c2aa98e2SPeter Wemm /* 1037c2aa98e2SPeter Wemm ** If we are using MX matches and have 1038c2aa98e2SPeter Wemm ** not yet gotten one, save this one 1039c2aa98e2SPeter Wemm ** but keep searching for an A or 1040c2aa98e2SPeter Wemm ** CNAME match. 1041c2aa98e2SPeter Wemm */ 1042c2aa98e2SPeter Wemm 1043c2aa98e2SPeter Wemm if (trymx && mxmatch == NULL) 1044c2aa98e2SPeter Wemm mxmatch = *dp; 1045c2aa98e2SPeter Wemm continue; 1046c2aa98e2SPeter Wemm } 1047c2aa98e2SPeter Wemm 1048c2aa98e2SPeter Wemm /* 1049c2aa98e2SPeter Wemm ** If we did not append a domain name, this 1050c2aa98e2SPeter Wemm ** must have been a canonical name to start 1051c2aa98e2SPeter Wemm ** with. Even if we did append a domain name, 1052c2aa98e2SPeter Wemm ** in the absence of a wildcard MX this must 1053c2aa98e2SPeter Wemm ** still be a real MX match. 1054c2aa98e2SPeter Wemm ** Such MX matches are as good as an A match, 1055c2aa98e2SPeter Wemm ** fall through. 1056c2aa98e2SPeter Wemm */ 105706f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 105806f25ae9SGregory Neil Shapiro 105906f25ae9SGregory Neil Shapiro # if NETINET6 106006f25ae9SGregory Neil Shapiro case T_AAAA: 106106f25ae9SGregory Neil Shapiro /* Flag that a good match was found */ 106240266059SGregory Neil Shapiro amatch = true; 106306f25ae9SGregory Neil Shapiro 106406f25ae9SGregory Neil Shapiro /* continue in case a CNAME also exists */ 106506f25ae9SGregory Neil Shapiro continue; 106606f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 1067c2aa98e2SPeter Wemm 1068c2aa98e2SPeter Wemm case T_A: 1069c2aa98e2SPeter Wemm /* Flag that a good match was found */ 107040266059SGregory Neil Shapiro amatch = true; 1071c2aa98e2SPeter Wemm 1072c2aa98e2SPeter Wemm /* continue in case a CNAME also exists */ 1073c2aa98e2SPeter Wemm continue; 1074c2aa98e2SPeter Wemm 1075c2aa98e2SPeter Wemm case T_CNAME: 1076c2aa98e2SPeter Wemm if (DontExpandCnames) 1077c2aa98e2SPeter Wemm { 1078c2aa98e2SPeter Wemm /* got CNAME -- guaranteed canonical */ 107940266059SGregory Neil Shapiro amatch = true; 1080c2aa98e2SPeter Wemm break; 1081c2aa98e2SPeter Wemm } 1082c2aa98e2SPeter Wemm 1083c2aa98e2SPeter Wemm if (loopcnt++ > MAXCNAMEDEPTH) 1084c2aa98e2SPeter Wemm { 1085c2aa98e2SPeter Wemm /*XXX should notify postmaster XXX*/ 1086c2aa98e2SPeter Wemm message("DNS failure: CNAME loop for %s", 1087c2aa98e2SPeter Wemm host); 1088c2aa98e2SPeter Wemm if (CurEnv->e_message == NULL) 1089c2aa98e2SPeter Wemm { 1090c2aa98e2SPeter Wemm char ebuf[MAXLINE]; 1091c2aa98e2SPeter Wemm 109240266059SGregory Neil Shapiro (void) sm_snprintf(ebuf, 109340266059SGregory Neil Shapiro sizeof ebuf, 1094c2aa98e2SPeter Wemm "Deferred: DNS failure: CNAME loop for %.100s", 1095c2aa98e2SPeter Wemm host); 109640266059SGregory Neil Shapiro CurEnv->e_message = 109740266059SGregory Neil Shapiro sm_rpool_strdup_x( 109840266059SGregory Neil Shapiro CurEnv->e_rpool, ebuf); 1099c2aa98e2SPeter Wemm } 1100602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(NO_RECOVERY); 1101c2aa98e2SPeter Wemm *statp = EX_CONFIG; 110240266059SGregory Neil Shapiro return false; 1103c2aa98e2SPeter Wemm } 1104c2aa98e2SPeter Wemm 1105c2aa98e2SPeter Wemm /* value points at name */ 110640266059SGregory Neil Shapiro if ((ret = dn_expand((unsigned char *)&answer, 110740266059SGregory Neil Shapiro eom, ap, (RES_UNC_T) nbuf, 110840266059SGregory Neil Shapiro sizeof(nbuf))) < 0) 1109c2aa98e2SPeter Wemm break; 111040266059SGregory Neil Shapiro (void) sm_strlcpy(host, nbuf, hbsize); 1111c2aa98e2SPeter Wemm 1112c2aa98e2SPeter Wemm /* 1113c2aa98e2SPeter Wemm ** RFC 1034 section 3.6 specifies that CNAME 1114c2aa98e2SPeter Wemm ** should point at the canonical name -- but 1115c2aa98e2SPeter Wemm ** urges software to try again anyway. 1116c2aa98e2SPeter Wemm */ 1117c2aa98e2SPeter Wemm 1118c2aa98e2SPeter Wemm goto cnameloop; 1119c2aa98e2SPeter Wemm 1120c2aa98e2SPeter Wemm default: 1121c2aa98e2SPeter Wemm /* not a record of interest */ 1122c2aa98e2SPeter Wemm continue; 1123c2aa98e2SPeter Wemm } 1124c2aa98e2SPeter Wemm } 1125c2aa98e2SPeter Wemm 1126c2aa98e2SPeter Wemm if (amatch) 1127c2aa98e2SPeter Wemm { 1128c2aa98e2SPeter Wemm /* 1129c2aa98e2SPeter Wemm ** Got a good match -- either an A, CNAME, or an 1130c2aa98e2SPeter Wemm ** exact MX record. Save it and get out of here. 1131c2aa98e2SPeter Wemm */ 1132c2aa98e2SPeter Wemm 1133c2aa98e2SPeter Wemm mxmatch = *dp; 1134c2aa98e2SPeter Wemm break; 1135c2aa98e2SPeter Wemm } 1136c2aa98e2SPeter Wemm 1137c2aa98e2SPeter Wemm /* 1138c2aa98e2SPeter Wemm ** Nothing definitive yet. 1139c2aa98e2SPeter Wemm ** If this was a T_A query and we haven't yet found a MX 1140c2aa98e2SPeter Wemm ** match, try T_MX if allowed to do so. 1141c2aa98e2SPeter Wemm ** Otherwise, try the next domain. 1142c2aa98e2SPeter Wemm */ 1143c2aa98e2SPeter Wemm 114406f25ae9SGregory Neil Shapiro # if NETINET6 114540266059SGregory Neil Shapiro if (qtype == T_AAAA) 1146c2aa98e2SPeter Wemm qtype = T_A; 114740266059SGregory Neil Shapiro else 114806f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 114940266059SGregory Neil Shapiro if (qtype == T_A && !gotmx && (trymx || **dp == '\0')) 1150c2aa98e2SPeter Wemm qtype = T_MX; 1151c2aa98e2SPeter Wemm else 1152c2aa98e2SPeter Wemm { 115340266059SGregory Neil Shapiro qtype = SM_T_INITIAL; 1154c2aa98e2SPeter Wemm dp++; 1155c2aa98e2SPeter Wemm } 1156c2aa98e2SPeter Wemm } 1157c2aa98e2SPeter Wemm 1158c2aa98e2SPeter Wemm /* if nothing was found, we are done */ 1159c2aa98e2SPeter Wemm if (mxmatch == NULL) 1160c2aa98e2SPeter Wemm { 1161193538b7SGregory Neil Shapiro if (*statp == EX_OK) 1162c2aa98e2SPeter Wemm *statp = EX_NOHOST; 116340266059SGregory Neil Shapiro return false; 1164c2aa98e2SPeter Wemm } 1165c2aa98e2SPeter Wemm 1166c2aa98e2SPeter Wemm /* 1167c2aa98e2SPeter Wemm ** Create canonical name and return. 1168c2aa98e2SPeter Wemm ** If saved domain name is null, name was already canonical. 1169c2aa98e2SPeter Wemm ** Otherwise append the saved domain name. 1170c2aa98e2SPeter Wemm */ 1171c2aa98e2SPeter Wemm 117240266059SGregory Neil Shapiro (void) sm_snprintf(nbuf, sizeof nbuf, "%.*s%s%.*s", MAXDNAME, host, 1173c2aa98e2SPeter Wemm *mxmatch == '\0' ? "" : ".", 1174c2aa98e2SPeter Wemm MAXDNAME, mxmatch); 117540266059SGregory Neil Shapiro (void) sm_strlcpy(host, nbuf, hbsize); 1176c2aa98e2SPeter Wemm if (tTd(8, 5)) 117740266059SGregory Neil Shapiro sm_dprintf("dns_getcanonname: %s\n", host); 1178c2aa98e2SPeter Wemm *statp = EX_OK; 117940266059SGregory Neil Shapiro 118040266059SGregory Neil Shapiro /* return only one TTL entry, that should be sufficient */ 118140266059SGregory Neil Shapiro if (ttl > 0 && pttl != NULL) 118240266059SGregory Neil Shapiro *pttl = ttl; 118340266059SGregory Neil Shapiro return true; 1184c2aa98e2SPeter Wemm } 1185c2aa98e2SPeter Wemm 118606f25ae9SGregory Neil Shapiro static char * 1187c2aa98e2SPeter Wemm gethostalias(host) 1188c2aa98e2SPeter Wemm char *host; 1189c2aa98e2SPeter Wemm { 1190c2aa98e2SPeter Wemm char *fname; 119140266059SGregory Neil Shapiro SM_FILE_T *fp; 1192c2aa98e2SPeter Wemm register char *p = NULL; 119306f25ae9SGregory Neil Shapiro long sff = SFF_REGONLY; 1194c2aa98e2SPeter Wemm char buf[MAXLINE]; 1195c2aa98e2SPeter Wemm static char hbuf[MAXDNAME]; 1196c2aa98e2SPeter Wemm 119740266059SGregory Neil Shapiro if (ResNoAliases) 119840266059SGregory Neil Shapiro return NULL; 1199c2aa98e2SPeter Wemm if (DontLockReadFiles) 1200c2aa98e2SPeter Wemm sff |= SFF_NOLOCK; 1201c2aa98e2SPeter Wemm fname = getenv("HOSTALIASES"); 1202c2aa98e2SPeter Wemm if (fname == NULL || 1203c2aa98e2SPeter Wemm (fp = safefopen(fname, O_RDONLY, 0, sff)) == NULL) 1204c2aa98e2SPeter Wemm return NULL; 120540266059SGregory Neil Shapiro while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) 1206c2aa98e2SPeter Wemm { 1207c2aa98e2SPeter Wemm for (p = buf; p != '\0' && !(isascii(*p) && isspace(*p)); p++) 1208c2aa98e2SPeter Wemm continue; 1209c2aa98e2SPeter Wemm if (*p == 0) 1210c2aa98e2SPeter Wemm { 1211c2aa98e2SPeter Wemm /* syntax error */ 1212c2aa98e2SPeter Wemm continue; 1213c2aa98e2SPeter Wemm } 1214c2aa98e2SPeter Wemm *p++ = '\0'; 121540266059SGregory Neil Shapiro if (sm_strcasecmp(buf, host) == 0) 1216c2aa98e2SPeter Wemm break; 1217c2aa98e2SPeter Wemm } 1218c2aa98e2SPeter Wemm 121940266059SGregory Neil Shapiro if (sm_io_eof(fp)) 1220c2aa98e2SPeter Wemm { 1221c2aa98e2SPeter Wemm /* no match */ 122240266059SGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 1223c2aa98e2SPeter Wemm return NULL; 1224c2aa98e2SPeter Wemm } 122540266059SGregory Neil Shapiro (void) sm_io_close(fp, SM_TIME_DEFAULT); 1226c2aa98e2SPeter Wemm 1227c2aa98e2SPeter Wemm /* got a match; extract the equivalent name */ 1228c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 1229c2aa98e2SPeter Wemm p++; 1230c2aa98e2SPeter Wemm host = p; 1231c2aa98e2SPeter Wemm while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1232c2aa98e2SPeter Wemm p++; 1233c2aa98e2SPeter Wemm *p = '\0'; 123440266059SGregory Neil Shapiro (void) sm_strlcpy(hbuf, host, sizeof hbuf); 1235c2aa98e2SPeter Wemm return hbuf; 1236c2aa98e2SPeter Wemm } 1237c2aa98e2SPeter Wemm #endif /* NAMED_BIND */ 1238