1c2aa98e2SPeter Wemm /* 25dd76dd0SGregory Neil Shapiro * Copyright (c) 1998-2004, 2006, 2010 Proofpoint, 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> 15d0cef73dSGregory Neil Shapiro #include "map.h" 16c2aa98e2SPeter Wemm 17c2aa98e2SPeter Wemm #if NAMED_BIND 18*4313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (with name server)") 1906f25ae9SGregory Neil Shapiro #else /* NAMED_BIND */ 20*4313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (without name server)") 2106f25ae9SGregory Neil Shapiro #endif /* NAMED_BIND */ 22c2aa98e2SPeter Wemm 23c2aa98e2SPeter Wemm #if NAMED_BIND 24c2aa98e2SPeter Wemm 25c2aa98e2SPeter Wemm # include <arpa/inet.h> 26c2aa98e2SPeter Wemm 2740266059SGregory Neil Shapiro 28c2aa98e2SPeter Wemm # ifndef MXHOSTBUFSIZE 29c2aa98e2SPeter Wemm # define MXHOSTBUFSIZE (128 * MAXMXHOSTS) 3006f25ae9SGregory Neil Shapiro # endif /* ! MXHOSTBUFSIZE */ 31c2aa98e2SPeter Wemm 32c2aa98e2SPeter Wemm static char MXHostBuf[MXHOSTBUFSIZE]; 3340266059SGregory Neil Shapiro #if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2) 3440266059SGregory Neil Shapiro ERROR: _MXHOSTBUFSIZE is out of range 3540266059SGregory Neil Shapiro #endif /* (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2) */ 36c2aa98e2SPeter Wemm 37c2aa98e2SPeter Wemm # ifndef MAXDNSRCH 38c2aa98e2SPeter Wemm # define MAXDNSRCH 6 /* number of possible domains to search */ 3906f25ae9SGregory Neil Shapiro # endif /* ! MAXDNSRCH */ 4006f25ae9SGregory Neil Shapiro 4106f25ae9SGregory Neil Shapiro # ifndef RES_DNSRCH_VARIABLE 4206f25ae9SGregory Neil Shapiro # define RES_DNSRCH_VARIABLE _res.dnsrch 4306f25ae9SGregory Neil Shapiro # endif /* ! RES_DNSRCH_VARIABLE */ 44c2aa98e2SPeter Wemm 45c2aa98e2SPeter Wemm # ifndef NO_DATA 46c2aa98e2SPeter Wemm # define NO_DATA NO_ADDRESS 4706f25ae9SGregory Neil Shapiro # endif /* ! NO_DATA */ 48c2aa98e2SPeter Wemm 49c2aa98e2SPeter Wemm # ifndef HFIXEDSZ 50c2aa98e2SPeter Wemm # define HFIXEDSZ 12 /* sizeof(HEADER) */ 5106f25ae9SGregory Neil Shapiro # endif /* ! HFIXEDSZ */ 52c2aa98e2SPeter Wemm 53c2aa98e2SPeter Wemm # define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */ 54c2aa98e2SPeter Wemm 55c2aa98e2SPeter Wemm # if defined(__RES) && (__RES >= 19940415) 56c2aa98e2SPeter Wemm # define RES_UNC_T char * 5706f25ae9SGregory Neil Shapiro # else /* defined(__RES) && (__RES >= 19940415) */ 5840266059SGregory Neil Shapiro # define RES_UNC_T unsigned char * 5906f25ae9SGregory Neil Shapiro # endif /* defined(__RES) && (__RES >= 19940415) */ 6006f25ae9SGregory Neil Shapiro 6106f25ae9SGregory Neil Shapiro static int mxrand __P((char *)); 6240266059SGregory Neil Shapiro static int fallbackmxrr __P((int, unsigned short *, char **)); 6306f25ae9SGregory Neil Shapiro 6440266059SGregory Neil Shapiro /* 6540266059SGregory Neil Shapiro ** GETFALLBACKMXRR -- get MX resource records for fallback MX host. 6640266059SGregory Neil Shapiro ** 6740266059SGregory Neil Shapiro ** We have to initialize this once before doing anything else. 6840266059SGregory Neil Shapiro ** Moreover, we have to repeat this from time to time to avoid 6940266059SGregory Neil Shapiro ** stale data, e.g., in persistent queue runners. 7040266059SGregory Neil Shapiro ** This should be done in a parent process so the child 7140266059SGregory Neil Shapiro ** processes have the right data. 7240266059SGregory Neil Shapiro ** 7340266059SGregory Neil Shapiro ** Parameters: 7440266059SGregory Neil Shapiro ** host -- the name of the fallback MX host. 7540266059SGregory Neil Shapiro ** 7640266059SGregory Neil Shapiro ** Returns: 7740266059SGregory Neil Shapiro ** number of MX records. 7840266059SGregory Neil Shapiro ** 7940266059SGregory Neil Shapiro ** Side Effects: 80e92d3f3fSGregory Neil Shapiro ** Populates NumFallbackMXHosts and fbhosts. 8140266059SGregory Neil Shapiro ** Sets renewal time (based on TTL). 8240266059SGregory Neil Shapiro */ 8340266059SGregory Neil Shapiro 84e92d3f3fSGregory Neil Shapiro int NumFallbackMXHosts = 0; /* Number of fallback MX hosts (after MX expansion) */ 8540266059SGregory Neil Shapiro static char *fbhosts[MAXMXHOSTS + 1]; 8640266059SGregory Neil Shapiro 8740266059SGregory Neil Shapiro int 8840266059SGregory Neil Shapiro getfallbackmxrr(host) 8940266059SGregory Neil Shapiro char *host; 9040266059SGregory Neil Shapiro { 9140266059SGregory Neil Shapiro int i, rcode; 9240266059SGregory Neil Shapiro int ttl; 9340266059SGregory Neil Shapiro static time_t renew = 0; 9440266059SGregory Neil Shapiro 9540266059SGregory Neil Shapiro #if 0 9640266059SGregory Neil Shapiro /* This is currently done before this function is called. */ 9740266059SGregory Neil Shapiro if (host == NULL || *host == '\0') 9840266059SGregory Neil Shapiro return 0; 9940266059SGregory Neil Shapiro #endif /* 0 */ 100e92d3f3fSGregory Neil Shapiro if (NumFallbackMXHosts > 0 && renew > curtime()) 101e92d3f3fSGregory Neil Shapiro return NumFallbackMXHosts; 10240266059SGregory Neil Shapiro if (host[0] == '[') 10340266059SGregory Neil Shapiro { 10440266059SGregory Neil Shapiro fbhosts[0] = host; 105e92d3f3fSGregory Neil Shapiro NumFallbackMXHosts = 1; 10640266059SGregory Neil Shapiro } 10740266059SGregory Neil Shapiro else 10840266059SGregory Neil Shapiro { 10940266059SGregory Neil Shapiro /* free old data */ 110e92d3f3fSGregory Neil Shapiro for (i = 0; i < NumFallbackMXHosts; i++) 11140266059SGregory Neil Shapiro sm_free(fbhosts[i]); 11240266059SGregory Neil Shapiro 11340266059SGregory Neil Shapiro /* get new data */ 114e92d3f3fSGregory Neil Shapiro NumFallbackMXHosts = getmxrr(host, fbhosts, NULL, false, 11540266059SGregory Neil Shapiro &rcode, false, &ttl); 11640266059SGregory Neil Shapiro renew = curtime() + ttl; 117e92d3f3fSGregory Neil Shapiro for (i = 0; i < NumFallbackMXHosts; i++) 11840266059SGregory Neil Shapiro fbhosts[i] = newstr(fbhosts[i]); 11940266059SGregory Neil Shapiro } 120e92d3f3fSGregory Neil Shapiro return NumFallbackMXHosts; 12140266059SGregory Neil Shapiro } 12240266059SGregory Neil Shapiro 12340266059SGregory Neil Shapiro /* 12440266059SGregory Neil Shapiro ** FALLBACKMXRR -- add MX resource records for fallback MX host to list. 12540266059SGregory Neil Shapiro ** 12640266059SGregory Neil Shapiro ** Parameters: 12740266059SGregory Neil Shapiro ** nmx -- current number of MX records. 12840266059SGregory Neil Shapiro ** prefs -- array of preferences. 12940266059SGregory Neil Shapiro ** mxhosts -- array of MX hosts (maximum size: MAXMXHOSTS) 13040266059SGregory Neil Shapiro ** 13140266059SGregory Neil Shapiro ** Returns: 13240266059SGregory Neil Shapiro ** new number of MX records. 13340266059SGregory Neil Shapiro ** 13440266059SGregory Neil Shapiro ** Side Effects: 135e92d3f3fSGregory Neil Shapiro ** If FallbackMX was set, it appends the MX records for 13640266059SGregory Neil Shapiro ** that host to mxhosts (and modifies prefs accordingly). 13740266059SGregory Neil Shapiro */ 13840266059SGregory Neil Shapiro 13940266059SGregory Neil Shapiro static int 14040266059SGregory Neil Shapiro fallbackmxrr(nmx, prefs, mxhosts) 14140266059SGregory Neil Shapiro int nmx; 14240266059SGregory Neil Shapiro unsigned short *prefs; 14340266059SGregory Neil Shapiro char **mxhosts; 14440266059SGregory Neil Shapiro { 14540266059SGregory Neil Shapiro int i; 14640266059SGregory Neil Shapiro 147e92d3f3fSGregory Neil Shapiro for (i = 0; i < NumFallbackMXHosts && nmx < MAXMXHOSTS; i++) 14840266059SGregory Neil Shapiro { 14940266059SGregory Neil Shapiro if (nmx > 0) 15040266059SGregory Neil Shapiro prefs[nmx] = prefs[nmx - 1] + 1; 15140266059SGregory Neil Shapiro else 15240266059SGregory Neil Shapiro prefs[nmx] = 0; 15340266059SGregory Neil Shapiro mxhosts[nmx++] = fbhosts[i]; 15440266059SGregory Neil Shapiro } 15540266059SGregory Neil Shapiro return nmx; 15640266059SGregory Neil Shapiro } 15740266059SGregory Neil Shapiro 15840266059SGregory Neil Shapiro /* 159c2aa98e2SPeter Wemm ** GETMXRR -- get MX resource records for a domain 160c2aa98e2SPeter Wemm ** 161c2aa98e2SPeter Wemm ** Parameters: 162c2aa98e2SPeter Wemm ** host -- the name of the host to MX. 163c2aa98e2SPeter Wemm ** mxhosts -- a pointer to a return buffer of MX records. 16406f25ae9SGregory Neil Shapiro ** mxprefs -- a pointer to a return buffer of MX preferences. 16506f25ae9SGregory Neil Shapiro ** If NULL, don't try to populate. 16640266059SGregory Neil Shapiro ** droplocalhost -- If true, all MX records less preferred 167c2aa98e2SPeter Wemm ** than the local host (as determined by $=w) will 168c2aa98e2SPeter Wemm ** be discarded. 169c2aa98e2SPeter Wemm ** rcode -- a pointer to an EX_ status code. 17040266059SGregory Neil Shapiro ** tryfallback -- add also fallback MX host? 17140266059SGregory Neil Shapiro ** pttl -- pointer to return TTL (can be NULL). 172c2aa98e2SPeter Wemm ** 173c2aa98e2SPeter Wemm ** Returns: 174c2aa98e2SPeter Wemm ** The number of MX records found. 175c2aa98e2SPeter Wemm ** -1 if there is an internal failure. 176c2aa98e2SPeter Wemm ** If no MX records are found, mxhosts[0] is set to host 177c2aa98e2SPeter Wemm ** and 1 is returned. 17840266059SGregory Neil Shapiro ** 17940266059SGregory Neil Shapiro ** Side Effects: 18040266059SGregory Neil Shapiro ** The entries made for mxhosts point to a static array 18140266059SGregory Neil Shapiro ** MXHostBuf[MXHOSTBUFSIZE], so the data needs to be copied, 18240266059SGregory Neil Shapiro ** if it must be preserved across calls to this function. 183c2aa98e2SPeter Wemm */ 184c2aa98e2SPeter Wemm 185c2aa98e2SPeter Wemm int 18640266059SGregory Neil Shapiro getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl) 187c2aa98e2SPeter Wemm char *host; 188c2aa98e2SPeter Wemm char **mxhosts; 18940266059SGregory Neil Shapiro unsigned short *mxprefs; 190c2aa98e2SPeter Wemm bool droplocalhost; 191c2aa98e2SPeter Wemm int *rcode; 19240266059SGregory Neil Shapiro bool tryfallback; 19340266059SGregory Neil Shapiro int *pttl; 194c2aa98e2SPeter Wemm { 19540266059SGregory Neil Shapiro register unsigned char *eom, *cp; 196c2aa98e2SPeter Wemm register int i, j, n; 197c2aa98e2SPeter Wemm int nmx = 0; 198c2aa98e2SPeter Wemm register char *bp; 199c2aa98e2SPeter Wemm HEADER *hp; 200c2aa98e2SPeter Wemm querybuf answer; 201c2aa98e2SPeter Wemm int ancount, qdcount, buflen; 20240266059SGregory Neil Shapiro bool seenlocal = false; 20340266059SGregory Neil Shapiro unsigned short pref, type; 20440266059SGregory Neil Shapiro unsigned short localpref = 256; 205e92d3f3fSGregory Neil Shapiro char *fallbackMX = FallbackMX; 20640266059SGregory Neil Shapiro bool trycanon = false; 20740266059SGregory Neil Shapiro unsigned short *prefs; 208b6bacd31SGregory Neil Shapiro int (*resfunc) __P((const char *, int, int, u_char *, int)); 20940266059SGregory Neil Shapiro unsigned short prefer[MAXMXHOSTS]; 210c2aa98e2SPeter Wemm int weight[MAXMXHOSTS]; 21140266059SGregory Neil Shapiro int ttl = 0; 21206f25ae9SGregory Neil Shapiro extern int res_query(), res_search(); 213c2aa98e2SPeter Wemm 214c2aa98e2SPeter Wemm if (tTd(8, 2)) 21540266059SGregory Neil Shapiro sm_dprintf("getmxrr(%s, droplocalhost=%d)\n", 21606f25ae9SGregory Neil Shapiro host, droplocalhost); 21713d88268SGregory Neil Shapiro *rcode = EX_OK; 21813d88268SGregory Neil Shapiro if (pttl != NULL) 21913d88268SGregory Neil Shapiro *pttl = SM_DEFAULT_TTL; 220a7ec597cSGregory Neil Shapiro if (*host == '\0') 221a7ec597cSGregory Neil Shapiro return 0; 222c2aa98e2SPeter Wemm 22340266059SGregory Neil Shapiro if ((fallbackMX != NULL && droplocalhost && 22440266059SGregory Neil Shapiro wordinclass(fallbackMX, 'w')) || !tryfallback) 225c2aa98e2SPeter Wemm { 226c2aa98e2SPeter Wemm /* don't use fallback for this pass */ 227c2aa98e2SPeter Wemm fallbackMX = NULL; 228c2aa98e2SPeter Wemm } 229c2aa98e2SPeter Wemm 23006f25ae9SGregory Neil Shapiro if (mxprefs != NULL) 23106f25ae9SGregory Neil Shapiro prefs = mxprefs; 23206f25ae9SGregory Neil Shapiro else 23306f25ae9SGregory Neil Shapiro prefs = prefer; 23406f25ae9SGregory Neil Shapiro 235c2aa98e2SPeter Wemm /* efficiency hack -- numeric or non-MX lookups */ 236c2aa98e2SPeter Wemm if (host[0] == '[') 237c2aa98e2SPeter Wemm goto punt; 238c2aa98e2SPeter Wemm 239c2aa98e2SPeter Wemm /* 240c2aa98e2SPeter Wemm ** If we don't have MX records in our host switch, don't 241c2aa98e2SPeter Wemm ** try for MX records. Note that this really isn't "right", 242c2aa98e2SPeter Wemm ** since we might be set up to try NIS first and then DNS; 243c2aa98e2SPeter Wemm ** if the host is found in NIS we really shouldn't be doing 244c2aa98e2SPeter Wemm ** MX lookups. However, that should be a degenerate case. 245c2aa98e2SPeter Wemm */ 246c2aa98e2SPeter Wemm 247c2aa98e2SPeter Wemm if (!UseNameServer) 248c2aa98e2SPeter Wemm goto punt; 249c2aa98e2SPeter Wemm if (HasWildcardMX && ConfigLevel >= 6) 250c2aa98e2SPeter Wemm resfunc = res_query; 251c2aa98e2SPeter Wemm else 252c2aa98e2SPeter Wemm resfunc = res_search; 253c2aa98e2SPeter Wemm 254c2aa98e2SPeter Wemm errno = 0; 25540266059SGregory Neil Shapiro n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer, 25640266059SGregory Neil Shapiro sizeof(answer)); 257c2aa98e2SPeter Wemm if (n < 0) 258c2aa98e2SPeter Wemm { 259c2aa98e2SPeter Wemm if (tTd(8, 1)) 26040266059SGregory Neil Shapiro sm_dprintf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n", 261d0cef73dSGregory Neil Shapiro host, errno, h_errno); 262c2aa98e2SPeter Wemm switch (h_errno) 263c2aa98e2SPeter Wemm { 264c2aa98e2SPeter Wemm case NO_DATA: 26540266059SGregory Neil Shapiro trycanon = true; 26606f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 267c2aa98e2SPeter Wemm 268c2aa98e2SPeter Wemm case NO_RECOVERY: 269c2aa98e2SPeter Wemm /* no MX data on this host */ 270c2aa98e2SPeter Wemm goto punt; 271c2aa98e2SPeter Wemm 272c2aa98e2SPeter Wemm case HOST_NOT_FOUND: 273c2aa98e2SPeter Wemm # if BROKEN_RES_SEARCH 274c2aa98e2SPeter Wemm case 0: /* Ultrix resolver retns failure w/ h_errno=0 */ 27506f25ae9SGregory Neil Shapiro # endif /* BROKEN_RES_SEARCH */ 276c2aa98e2SPeter Wemm /* host doesn't exist in DNS; might be in /etc/hosts */ 27740266059SGregory Neil Shapiro trycanon = true; 278c2aa98e2SPeter Wemm *rcode = EX_NOHOST; 279c2aa98e2SPeter Wemm goto punt; 280c2aa98e2SPeter Wemm 281c2aa98e2SPeter Wemm case TRY_AGAIN: 282c2aa98e2SPeter Wemm case -1: 283c2aa98e2SPeter Wemm /* couldn't connect to the name server */ 284c2aa98e2SPeter Wemm if (fallbackMX != NULL) 285c2aa98e2SPeter Wemm { 286c2aa98e2SPeter Wemm /* name server is hosed -- push to fallback */ 28740266059SGregory Neil Shapiro return fallbackmxrr(nmx, prefs, mxhosts); 288c2aa98e2SPeter Wemm } 289c2aa98e2SPeter Wemm /* it might come up later; better queue it up */ 290c2aa98e2SPeter Wemm *rcode = EX_TEMPFAIL; 291c2aa98e2SPeter Wemm break; 292c2aa98e2SPeter Wemm 293c2aa98e2SPeter Wemm default: 29440266059SGregory Neil Shapiro syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)", 295c2aa98e2SPeter Wemm host, h_errno); 296c2aa98e2SPeter Wemm *rcode = EX_OSERR; 297c2aa98e2SPeter Wemm break; 298c2aa98e2SPeter Wemm } 299c2aa98e2SPeter Wemm 300c2aa98e2SPeter Wemm /* irreconcilable differences */ 30106f25ae9SGregory Neil Shapiro return -1; 302c2aa98e2SPeter Wemm } 303c2aa98e2SPeter Wemm 304c2aa98e2SPeter Wemm /* avoid problems after truncation in tcp packets */ 305c2aa98e2SPeter Wemm if (n > sizeof(answer)) 306c2aa98e2SPeter Wemm n = sizeof(answer); 307c2aa98e2SPeter Wemm 308c2aa98e2SPeter Wemm /* find first satisfactory answer */ 309c2aa98e2SPeter Wemm hp = (HEADER *)&answer; 31040266059SGregory Neil Shapiro cp = (unsigned char *)&answer + HFIXEDSZ; 31140266059SGregory Neil Shapiro eom = (unsigned char *)&answer + n; 31240266059SGregory Neil Shapiro for (qdcount = ntohs((unsigned short) hp->qdcount); 31306f25ae9SGregory Neil Shapiro qdcount--; 31406f25ae9SGregory Neil Shapiro cp += n + QFIXEDSZ) 31506f25ae9SGregory Neil Shapiro { 316c2aa98e2SPeter Wemm if ((n = dn_skipname(cp, eom)) < 0) 317c2aa98e2SPeter Wemm goto punt; 31806f25ae9SGregory Neil Shapiro } 31940266059SGregory Neil Shapiro 32040266059SGregory Neil Shapiro /* NOTE: see definition of MXHostBuf! */ 321c2aa98e2SPeter Wemm buflen = sizeof(MXHostBuf) - 1; 32240266059SGregory Neil Shapiro SM_ASSERT(buflen > 0); 323c2aa98e2SPeter Wemm bp = MXHostBuf; 32440266059SGregory Neil Shapiro ancount = ntohs((unsigned short) hp->ancount); 32540266059SGregory Neil Shapiro 32640266059SGregory Neil Shapiro /* See RFC 1035 for layout of RRs. */ 327e92d3f3fSGregory Neil Shapiro /* XXX leave room for FallbackMX ? */ 328c2aa98e2SPeter Wemm while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1) 329c2aa98e2SPeter Wemm { 33040266059SGregory Neil Shapiro if ((n = dn_expand((unsigned char *)&answer, eom, cp, 33140266059SGregory Neil Shapiro (RES_UNC_T) bp, buflen)) < 0) 332c2aa98e2SPeter Wemm break; 333c2aa98e2SPeter Wemm cp += n; 334c2aa98e2SPeter Wemm GETSHORT(type, cp); 33540266059SGregory Neil Shapiro cp += INT16SZ; /* skip over class */ 33640266059SGregory Neil Shapiro GETLONG(ttl, cp); 33740266059SGregory Neil Shapiro GETSHORT(n, cp); /* rdlength */ 338c2aa98e2SPeter Wemm if (type != T_MX) 339c2aa98e2SPeter Wemm { 340c2aa98e2SPeter Wemm if (tTd(8, 8) || _res.options & RES_DEBUG) 34140266059SGregory Neil Shapiro sm_dprintf("unexpected answer type %d, size %d\n", 342c2aa98e2SPeter Wemm type, n); 343c2aa98e2SPeter Wemm cp += n; 344c2aa98e2SPeter Wemm continue; 345c2aa98e2SPeter Wemm } 346c2aa98e2SPeter Wemm GETSHORT(pref, cp); 34740266059SGregory Neil Shapiro if ((n = dn_expand((unsigned char *)&answer, eom, cp, 348c2aa98e2SPeter Wemm (RES_UNC_T) bp, buflen)) < 0) 349c2aa98e2SPeter Wemm break; 350c2aa98e2SPeter Wemm cp += n; 35140266059SGregory Neil Shapiro n = strlen(bp); 35240266059SGregory Neil Shapiro # if 0 35340266059SGregory Neil Shapiro /* Can this happen? */ 35440266059SGregory Neil Shapiro if (n == 0) 35540266059SGregory Neil Shapiro { 35640266059SGregory Neil Shapiro if (LogLevel > 4) 35740266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 35840266059SGregory Neil Shapiro "MX records for %s contain empty string", 35940266059SGregory Neil Shapiro host); 36040266059SGregory Neil Shapiro continue; 36140266059SGregory Neil Shapiro } 36240266059SGregory Neil Shapiro # endif /* 0 */ 363c2aa98e2SPeter Wemm if (wordinclass(bp, 'w')) 364c2aa98e2SPeter Wemm { 365c2aa98e2SPeter Wemm if (tTd(8, 3)) 36640266059SGregory Neil Shapiro sm_dprintf("found localhost (%s) in MX list, pref=%d\n", 367c2aa98e2SPeter Wemm bp, pref); 368c2aa98e2SPeter Wemm if (droplocalhost) 369c2aa98e2SPeter Wemm { 370c2aa98e2SPeter Wemm if (!seenlocal || pref < localpref) 371c2aa98e2SPeter Wemm localpref = pref; 37240266059SGregory Neil Shapiro seenlocal = true; 373c2aa98e2SPeter Wemm continue; 374c2aa98e2SPeter Wemm } 375c2aa98e2SPeter Wemm weight[nmx] = 0; 376c2aa98e2SPeter Wemm } 377c2aa98e2SPeter Wemm else 378c2aa98e2SPeter Wemm weight[nmx] = mxrand(bp); 37906f25ae9SGregory Neil Shapiro prefs[nmx] = pref; 380c2aa98e2SPeter Wemm mxhosts[nmx++] = bp; 381c2aa98e2SPeter Wemm bp += n; 382c2aa98e2SPeter Wemm if (bp[-1] != '.') 383c2aa98e2SPeter Wemm { 384c2aa98e2SPeter Wemm *bp++ = '.'; 385c2aa98e2SPeter Wemm n++; 386c2aa98e2SPeter Wemm } 387c2aa98e2SPeter Wemm *bp++ = '\0'; 38840266059SGregory Neil Shapiro if (buflen < n + 1) 38940266059SGregory Neil Shapiro { 39040266059SGregory Neil Shapiro /* don't want to wrap buflen */ 39140266059SGregory Neil Shapiro break; 39240266059SGregory Neil Shapiro } 393c2aa98e2SPeter Wemm buflen -= n + 1; 394c2aa98e2SPeter Wemm } 395c2aa98e2SPeter Wemm 39640266059SGregory Neil Shapiro /* return only one TTL entry, that should be sufficient */ 39740266059SGregory Neil Shapiro if (ttl > 0 && pttl != NULL) 39840266059SGregory Neil Shapiro *pttl = ttl; 39940266059SGregory Neil Shapiro 400c2aa98e2SPeter Wemm /* sort the records */ 401c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 402c2aa98e2SPeter Wemm { 403c2aa98e2SPeter Wemm for (j = i + 1; j < nmx; j++) 404c2aa98e2SPeter Wemm { 40506f25ae9SGregory Neil Shapiro if (prefs[i] > prefs[j] || 40606f25ae9SGregory Neil Shapiro (prefs[i] == prefs[j] && weight[i] > weight[j])) 407c2aa98e2SPeter Wemm { 408c2aa98e2SPeter Wemm register int temp; 409c2aa98e2SPeter Wemm register char *temp1; 410c2aa98e2SPeter Wemm 41106f25ae9SGregory Neil Shapiro temp = prefs[i]; 41206f25ae9SGregory Neil Shapiro prefs[i] = prefs[j]; 41306f25ae9SGregory Neil Shapiro prefs[j] = temp; 414c2aa98e2SPeter Wemm temp1 = mxhosts[i]; 415c2aa98e2SPeter Wemm mxhosts[i] = mxhosts[j]; 416c2aa98e2SPeter Wemm mxhosts[j] = temp1; 417c2aa98e2SPeter Wemm temp = weight[i]; 418c2aa98e2SPeter Wemm weight[i] = weight[j]; 419c2aa98e2SPeter Wemm weight[j] = temp; 420c2aa98e2SPeter Wemm } 421c2aa98e2SPeter Wemm } 42206f25ae9SGregory Neil Shapiro if (seenlocal && prefs[i] >= localpref) 423c2aa98e2SPeter Wemm { 424c2aa98e2SPeter Wemm /* truncate higher preference part of list */ 425c2aa98e2SPeter Wemm nmx = i; 426c2aa98e2SPeter Wemm } 427c2aa98e2SPeter Wemm } 428c2aa98e2SPeter Wemm 429c2aa98e2SPeter Wemm /* delete duplicates from list (yes, some bozos have duplicates) */ 430c2aa98e2SPeter Wemm for (i = 0; i < nmx - 1; ) 431c2aa98e2SPeter Wemm { 43240266059SGregory Neil Shapiro if (sm_strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0) 433c2aa98e2SPeter Wemm i++; 434c2aa98e2SPeter Wemm else 435c2aa98e2SPeter Wemm { 436c2aa98e2SPeter Wemm /* compress out duplicate */ 437c2aa98e2SPeter Wemm for (j = i + 1; j < nmx; j++) 43806f25ae9SGregory Neil Shapiro { 439c2aa98e2SPeter Wemm mxhosts[j] = mxhosts[j + 1]; 44006f25ae9SGregory Neil Shapiro prefs[j] = prefs[j + 1]; 44106f25ae9SGregory Neil Shapiro } 442c2aa98e2SPeter Wemm nmx--; 443c2aa98e2SPeter Wemm } 444c2aa98e2SPeter Wemm } 445c2aa98e2SPeter Wemm 446c2aa98e2SPeter Wemm if (nmx == 0) 447c2aa98e2SPeter Wemm { 448c2aa98e2SPeter Wemm punt: 44906f25ae9SGregory Neil Shapiro if (seenlocal) 450c2aa98e2SPeter Wemm { 45106f25ae9SGregory Neil Shapiro struct hostent *h = NULL; 45206f25ae9SGregory Neil Shapiro 453c2aa98e2SPeter Wemm /* 454c2aa98e2SPeter Wemm ** If we have deleted all MX entries, this is 455c2aa98e2SPeter Wemm ** an error -- we should NEVER send to a host that 456c2aa98e2SPeter Wemm ** has an MX, and this should have been caught 457c2aa98e2SPeter Wemm ** earlier in the config file. 458c2aa98e2SPeter Wemm ** 459c2aa98e2SPeter Wemm ** Some sites prefer to go ahead and try the 460c2aa98e2SPeter Wemm ** A record anyway; that case is handled by 461c2aa98e2SPeter Wemm ** setting TryNullMXList. I believe this is a 462c2aa98e2SPeter Wemm ** bad idea, but it's up to you.... 463c2aa98e2SPeter Wemm */ 464c2aa98e2SPeter Wemm 46506f25ae9SGregory Neil Shapiro if (TryNullMXList) 46606f25ae9SGregory Neil Shapiro { 467602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 46806f25ae9SGregory Neil Shapiro errno = 0; 46906f25ae9SGregory Neil Shapiro h = sm_gethostbyname(host, AF_INET); 47006f25ae9SGregory Neil Shapiro if (h == NULL) 47106f25ae9SGregory Neil Shapiro { 47206f25ae9SGregory Neil Shapiro if (errno == ETIMEDOUT || 47306f25ae9SGregory Neil Shapiro h_errno == TRY_AGAIN || 47406f25ae9SGregory Neil Shapiro (errno == ECONNREFUSED && 47506f25ae9SGregory Neil Shapiro UseNameServer)) 47606f25ae9SGregory Neil Shapiro { 47706f25ae9SGregory Neil Shapiro *rcode = EX_TEMPFAIL; 47806f25ae9SGregory Neil Shapiro return -1; 47906f25ae9SGregory Neil Shapiro } 48006f25ae9SGregory Neil Shapiro # if NETINET6 481602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 48206f25ae9SGregory Neil Shapiro errno = 0; 48306f25ae9SGregory Neil Shapiro h = sm_gethostbyname(host, AF_INET6); 48406f25ae9SGregory Neil Shapiro if (h == NULL && 48506f25ae9SGregory Neil Shapiro (errno == ETIMEDOUT || 48606f25ae9SGregory Neil Shapiro h_errno == TRY_AGAIN || 48706f25ae9SGregory Neil Shapiro (errno == ECONNREFUSED && 48806f25ae9SGregory Neil Shapiro UseNameServer))) 48906f25ae9SGregory Neil Shapiro { 49006f25ae9SGregory Neil Shapiro *rcode = EX_TEMPFAIL; 49106f25ae9SGregory Neil Shapiro return -1; 49206f25ae9SGregory Neil Shapiro } 49306f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 49406f25ae9SGregory Neil Shapiro } 49506f25ae9SGregory Neil Shapiro } 49606f25ae9SGregory Neil Shapiro 49706f25ae9SGregory Neil Shapiro if (h == NULL) 49806f25ae9SGregory Neil Shapiro { 499c2aa98e2SPeter Wemm *rcode = EX_CONFIG; 500c2aa98e2SPeter Wemm syserr("MX list for %s points back to %s", 501c2aa98e2SPeter Wemm host, MyHostName); 502c2aa98e2SPeter Wemm return -1; 503c2aa98e2SPeter Wemm } 50440266059SGregory Neil Shapiro # if NETINET6 505193538b7SGregory Neil Shapiro freehostent(h); 506af9557fdSGregory Neil Shapiro h = NULL; 50740266059SGregory Neil Shapiro # endif /* NETINET6 */ 50806f25ae9SGregory Neil Shapiro } 509d0cef73dSGregory Neil Shapiro if (strlen(host) >= sizeof(MXHostBuf)) 510c2aa98e2SPeter Wemm { 511c2aa98e2SPeter Wemm *rcode = EX_CONFIG; 512c2aa98e2SPeter Wemm syserr("Host name %s too long", 513c2aa98e2SPeter Wemm shortenstring(host, MAXSHORTSTR)); 514c2aa98e2SPeter Wemm return -1; 515c2aa98e2SPeter Wemm } 516d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(MXHostBuf, host, sizeof(MXHostBuf)); 517c2aa98e2SPeter Wemm mxhosts[0] = MXHostBuf; 51806f25ae9SGregory Neil Shapiro prefs[0] = 0; 519c2aa98e2SPeter Wemm if (host[0] == '[') 520c2aa98e2SPeter Wemm { 521c2aa98e2SPeter Wemm register char *p; 52206f25ae9SGregory Neil Shapiro # if NETINET6 52306f25ae9SGregory Neil Shapiro struct sockaddr_in6 tmp6; 52406f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 525c2aa98e2SPeter Wemm 526c2aa98e2SPeter Wemm /* this may be an MX suppression-style address */ 527c2aa98e2SPeter Wemm p = strchr(MXHostBuf, ']'); 528c2aa98e2SPeter Wemm if (p != NULL) 529c2aa98e2SPeter Wemm { 530c2aa98e2SPeter Wemm *p = '\0'; 53106f25ae9SGregory Neil Shapiro 532c2aa98e2SPeter Wemm if (inet_addr(&MXHostBuf[1]) != INADDR_NONE) 533c2aa98e2SPeter Wemm { 534c2aa98e2SPeter Wemm nmx++; 535c2aa98e2SPeter Wemm *p = ']'; 536c2aa98e2SPeter Wemm } 53706f25ae9SGregory Neil Shapiro # if NETINET6 53840266059SGregory Neil Shapiro else if (anynet_pton(AF_INET6, &MXHostBuf[1], 53906f25ae9SGregory Neil Shapiro &tmp6.sin6_addr) == 1) 54006f25ae9SGregory Neil Shapiro { 54106f25ae9SGregory Neil Shapiro nmx++; 54206f25ae9SGregory Neil Shapiro *p = ']'; 54306f25ae9SGregory Neil Shapiro } 54406f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 545c2aa98e2SPeter Wemm else 546c2aa98e2SPeter Wemm { 54740266059SGregory Neil Shapiro trycanon = true; 548c2aa98e2SPeter Wemm mxhosts[0]++; 549c2aa98e2SPeter Wemm } 550c2aa98e2SPeter Wemm } 551c2aa98e2SPeter Wemm } 552c2aa98e2SPeter Wemm if (trycanon && 553d0cef73dSGregory Neil Shapiro getcanonname(mxhosts[0], sizeof(MXHostBuf) - 2, false, pttl)) 554c2aa98e2SPeter Wemm { 55540266059SGregory Neil Shapiro /* XXX MXHostBuf == "" ? is that possible? */ 556c2aa98e2SPeter Wemm bp = &MXHostBuf[strlen(MXHostBuf)]; 557c2aa98e2SPeter Wemm if (bp[-1] != '.') 558c2aa98e2SPeter Wemm { 559c2aa98e2SPeter Wemm *bp++ = '.'; 560c2aa98e2SPeter Wemm *bp = '\0'; 561c2aa98e2SPeter Wemm } 562c2aa98e2SPeter Wemm nmx = 1; 563c2aa98e2SPeter Wemm } 564c2aa98e2SPeter Wemm } 565c2aa98e2SPeter Wemm 566c2aa98e2SPeter Wemm /* if we have a default lowest preference, include that */ 567c2aa98e2SPeter Wemm if (fallbackMX != NULL && !seenlocal) 56806f25ae9SGregory Neil Shapiro { 56940266059SGregory Neil Shapiro nmx = fallbackmxrr(nmx, prefs, mxhosts); 57006f25ae9SGregory Neil Shapiro } 57106f25ae9SGregory Neil Shapiro return nmx; 572c2aa98e2SPeter Wemm } 57340266059SGregory Neil Shapiro /* 574c2aa98e2SPeter Wemm ** MXRAND -- create a randomizer for equal MX preferences 575c2aa98e2SPeter Wemm ** 576c2aa98e2SPeter Wemm ** If two MX hosts have equal preferences we want to randomize 577c2aa98e2SPeter Wemm ** the selection. But in order for signatures to be the same, 578c2aa98e2SPeter Wemm ** we need to randomize the same way each time. This function 579c2aa98e2SPeter Wemm ** computes a pseudo-random hash function from the host name. 580c2aa98e2SPeter Wemm ** 581c2aa98e2SPeter Wemm ** Parameters: 582c2aa98e2SPeter Wemm ** host -- the name of the host. 583c2aa98e2SPeter Wemm ** 584c2aa98e2SPeter Wemm ** Returns: 585c2aa98e2SPeter Wemm ** A random but repeatable value based on the host name. 586c2aa98e2SPeter Wemm */ 587c2aa98e2SPeter Wemm 58806f25ae9SGregory Neil Shapiro static int 589c2aa98e2SPeter Wemm mxrand(host) 590c2aa98e2SPeter Wemm register char *host; 591c2aa98e2SPeter Wemm { 592c2aa98e2SPeter Wemm int hfunc; 593c2aa98e2SPeter Wemm static unsigned int seed; 594c2aa98e2SPeter Wemm 595c2aa98e2SPeter Wemm if (seed == 0) 596c2aa98e2SPeter Wemm { 597c2aa98e2SPeter Wemm seed = (int) curtime() & 0xffff; 598c2aa98e2SPeter Wemm if (seed == 0) 599c2aa98e2SPeter Wemm seed++; 600c2aa98e2SPeter Wemm } 601c2aa98e2SPeter Wemm 602c2aa98e2SPeter Wemm if (tTd(17, 9)) 60340266059SGregory Neil Shapiro sm_dprintf("mxrand(%s)", host); 604c2aa98e2SPeter Wemm 605c2aa98e2SPeter Wemm hfunc = seed; 606c2aa98e2SPeter Wemm while (*host != '\0') 607c2aa98e2SPeter Wemm { 608c2aa98e2SPeter Wemm int c = *host++; 609c2aa98e2SPeter Wemm 610c2aa98e2SPeter Wemm if (isascii(c) && isupper(c)) 611c2aa98e2SPeter Wemm c = tolower(c); 612c2aa98e2SPeter Wemm hfunc = ((hfunc << 1) ^ c) % 2003; 613c2aa98e2SPeter Wemm } 614c2aa98e2SPeter Wemm 615c2aa98e2SPeter Wemm hfunc &= 0xff; 616c2aa98e2SPeter Wemm hfunc++; 617c2aa98e2SPeter Wemm 618c2aa98e2SPeter Wemm if (tTd(17, 9)) 61940266059SGregory Neil Shapiro sm_dprintf(" = %d\n", hfunc); 620c2aa98e2SPeter Wemm return hfunc; 621c2aa98e2SPeter Wemm } 62240266059SGregory Neil Shapiro /* 623c2aa98e2SPeter Wemm ** BESTMX -- find the best MX for a name 624c2aa98e2SPeter Wemm ** 625c2aa98e2SPeter Wemm ** This is really a hack, but I don't see any obvious way 626c2aa98e2SPeter Wemm ** to generalize it at the moment. 627c2aa98e2SPeter Wemm */ 628c2aa98e2SPeter Wemm 629c2aa98e2SPeter Wemm /* ARGSUSED3 */ 630c2aa98e2SPeter Wemm char * 631c2aa98e2SPeter Wemm bestmx_map_lookup(map, name, av, statp) 632c2aa98e2SPeter Wemm MAP *map; 633c2aa98e2SPeter Wemm char *name; 634c2aa98e2SPeter Wemm char **av; 635c2aa98e2SPeter Wemm int *statp; 636c2aa98e2SPeter Wemm { 637c2aa98e2SPeter Wemm int nmx; 638c2aa98e2SPeter Wemm int saveopts = _res.options; 63940266059SGregory Neil Shapiro int i; 64040266059SGregory Neil Shapiro ssize_t len = 0; 64140266059SGregory Neil Shapiro char *result; 642c2aa98e2SPeter Wemm char *mxhosts[MAXMXHOSTS + 1]; 64340266059SGregory Neil Shapiro #if _FFR_BESTMX_BETTER_TRUNCATION 64440266059SGregory Neil Shapiro char *buf; 64540266059SGregory Neil Shapiro #else /* _FFR_BESTMX_BETTER_TRUNCATION */ 64640266059SGregory Neil Shapiro char *p; 647065a643dSPeter Wemm char buf[PSBUFSIZE / 2]; 64840266059SGregory Neil Shapiro #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 649c2aa98e2SPeter Wemm 650c2aa98e2SPeter Wemm _res.options &= ~(RES_DNSRCH|RES_DEFNAMES); 651959366dcSGregory Neil Shapiro nmx = getmxrr(name, mxhosts, NULL, false, statp, false, NULL); 652c2aa98e2SPeter Wemm _res.options = saveopts; 653c2aa98e2SPeter Wemm if (nmx <= 0) 654c2aa98e2SPeter Wemm return NULL; 655c2aa98e2SPeter Wemm if (bitset(MF_MATCHONLY, map->map_mflags)) 656c2aa98e2SPeter Wemm return map_rewrite(map, name, strlen(name), NULL); 657c2aa98e2SPeter Wemm if ((map->map_coldelim == '\0') || (nmx == 1)) 658c2aa98e2SPeter Wemm return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av); 659c2aa98e2SPeter Wemm 660c2aa98e2SPeter Wemm /* 661c2aa98e2SPeter Wemm ** We were given a -z flag (return all MXs) and there are multiple 662c2aa98e2SPeter Wemm ** ones. We need to build them all into a list. 663c2aa98e2SPeter Wemm */ 66440266059SGregory Neil Shapiro 66540266059SGregory Neil Shapiro #if _FFR_BESTMX_BETTER_TRUNCATION 66640266059SGregory Neil Shapiro for (i = 0; i < nmx; i++) 66740266059SGregory Neil Shapiro { 66840266059SGregory Neil Shapiro if (strchr(mxhosts[i], map->map_coldelim) != NULL) 66940266059SGregory Neil Shapiro { 67040266059SGregory Neil Shapiro syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 67140266059SGregory Neil Shapiro mxhosts[i], map->map_coldelim); 67240266059SGregory Neil Shapiro return NULL; 67340266059SGregory Neil Shapiro } 67440266059SGregory Neil Shapiro len += strlen(mxhosts[i]) + 1; 67540266059SGregory Neil Shapiro if (len < 0) 67640266059SGregory Neil Shapiro { 67740266059SGregory Neil Shapiro len -= strlen(mxhosts[i]) + 1; 67840266059SGregory Neil Shapiro break; 67940266059SGregory Neil Shapiro } 68040266059SGregory Neil Shapiro } 68140266059SGregory Neil Shapiro buf = (char *) sm_malloc(len); 68240266059SGregory Neil Shapiro if (buf == NULL) 68340266059SGregory Neil Shapiro { 68440266059SGregory Neil Shapiro *statp = EX_UNAVAILABLE; 68540266059SGregory Neil Shapiro return NULL; 68640266059SGregory Neil Shapiro } 68740266059SGregory Neil Shapiro *buf = '\0'; 68840266059SGregory Neil Shapiro for (i = 0; i < nmx; i++) 68940266059SGregory Neil Shapiro { 69040266059SGregory Neil Shapiro int end; 69140266059SGregory Neil Shapiro 69240266059SGregory Neil Shapiro end = sm_strlcat(buf, mxhosts[i], len); 69340266059SGregory Neil Shapiro if (i != nmx && end + 1 < len) 69440266059SGregory Neil Shapiro { 69540266059SGregory Neil Shapiro buf[end] = map->map_coldelim; 69640266059SGregory Neil Shapiro buf[end + 1] = '\0'; 69740266059SGregory Neil Shapiro } 69840266059SGregory Neil Shapiro } 69940266059SGregory Neil Shapiro 70040266059SGregory Neil Shapiro /* Cleanly truncate for rulesets */ 70140266059SGregory Neil Shapiro truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim); 70240266059SGregory Neil Shapiro #else /* _FFR_BESTMX_BETTER_TRUNCATION */ 703c2aa98e2SPeter Wemm p = buf; 704c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 705c2aa98e2SPeter Wemm { 70640266059SGregory Neil Shapiro size_t slen; 707c2aa98e2SPeter Wemm 708c2aa98e2SPeter Wemm if (strchr(mxhosts[i], map->map_coldelim) != NULL) 709c2aa98e2SPeter Wemm { 710c2aa98e2SPeter Wemm syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 711c2aa98e2SPeter Wemm mxhosts[i], map->map_coldelim); 712c2aa98e2SPeter Wemm return NULL; 713c2aa98e2SPeter Wemm } 714c2aa98e2SPeter Wemm slen = strlen(mxhosts[i]); 715d0cef73dSGregory Neil Shapiro if (len + slen + 2 > sizeof(buf)) 716c2aa98e2SPeter Wemm break; 717c2aa98e2SPeter Wemm if (i > 0) 718c2aa98e2SPeter Wemm { 719c2aa98e2SPeter Wemm *p++ = map->map_coldelim; 720c2aa98e2SPeter Wemm len++; 721c2aa98e2SPeter Wemm } 722d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(p, mxhosts[i], sizeof(buf) - len); 723c2aa98e2SPeter Wemm p += slen; 724c2aa98e2SPeter Wemm len += slen; 725c2aa98e2SPeter Wemm } 72640266059SGregory Neil Shapiro #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 72740266059SGregory Neil Shapiro 72840266059SGregory Neil Shapiro result = map_rewrite(map, buf, len, av); 72940266059SGregory Neil Shapiro #if _FFR_BESTMX_BETTER_TRUNCATION 73040266059SGregory Neil Shapiro sm_free(buf); 73140266059SGregory Neil Shapiro #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 73240266059SGregory Neil Shapiro return result; 733c2aa98e2SPeter Wemm } 73440266059SGregory Neil Shapiro /* 735c2aa98e2SPeter Wemm ** DNS_GETCANONNAME -- get the canonical name for named host using DNS 736c2aa98e2SPeter Wemm ** 737c2aa98e2SPeter Wemm ** This algorithm tries to be smart about wildcard MX records. 738c2aa98e2SPeter Wemm ** This is hard to do because DNS doesn't tell is if we matched 739c2aa98e2SPeter Wemm ** against a wildcard or a specific MX. 740c2aa98e2SPeter Wemm ** 741c2aa98e2SPeter Wemm ** We always prefer A & CNAME records, since these are presumed 742c2aa98e2SPeter Wemm ** to be specific. 743c2aa98e2SPeter Wemm ** 744c2aa98e2SPeter Wemm ** If we match an MX in one pass and lose it in the next, we use 745c2aa98e2SPeter Wemm ** the old one. For example, consider an MX matching *.FOO.BAR.COM. 746c2aa98e2SPeter Wemm ** A hostname bletch.foo.bar.com will match against this MX, but 747c2aa98e2SPeter Wemm ** will stop matching when we try bletch.bar.com -- so we know 748c2aa98e2SPeter Wemm ** that bletch.foo.bar.com must have been right. This fails if 749c2aa98e2SPeter Wemm ** there was also an MX record matching *.BAR.COM, but there are 750c2aa98e2SPeter Wemm ** some things that just can't be fixed. 751c2aa98e2SPeter Wemm ** 752c2aa98e2SPeter Wemm ** Parameters: 753c2aa98e2SPeter Wemm ** host -- a buffer containing the name of the host. 754c2aa98e2SPeter Wemm ** This is a value-result parameter. 755c2aa98e2SPeter Wemm ** hbsize -- the size of the host buffer. 756c2aa98e2SPeter Wemm ** trymx -- if set, try MX records as well as A and CNAME. 757c2aa98e2SPeter Wemm ** statp -- pointer to place to store status. 75840266059SGregory Neil Shapiro ** pttl -- pointer to return TTL (can be NULL). 759c2aa98e2SPeter Wemm ** 760c2aa98e2SPeter Wemm ** Returns: 76140266059SGregory Neil Shapiro ** true -- if the host matched. 76240266059SGregory Neil Shapiro ** false -- otherwise. 763c2aa98e2SPeter Wemm */ 764c2aa98e2SPeter Wemm 765c2aa98e2SPeter Wemm bool 76640266059SGregory Neil Shapiro dns_getcanonname(host, hbsize, trymx, statp, pttl) 767c2aa98e2SPeter Wemm char *host; 768c2aa98e2SPeter Wemm int hbsize; 769c2aa98e2SPeter Wemm bool trymx; 770c2aa98e2SPeter Wemm int *statp; 77140266059SGregory Neil Shapiro int *pttl; 772c2aa98e2SPeter Wemm { 77340266059SGregory Neil Shapiro register unsigned char *eom, *ap; 774c2aa98e2SPeter Wemm register char *cp; 775c2aa98e2SPeter Wemm register int n; 776c2aa98e2SPeter Wemm HEADER *hp; 777c2aa98e2SPeter Wemm querybuf answer; 778c2aa98e2SPeter Wemm int ancount, qdcount; 779c2aa98e2SPeter Wemm int ret; 780c2aa98e2SPeter Wemm char **domain; 781c2aa98e2SPeter Wemm int type; 78240266059SGregory Neil Shapiro int ttl = 0; 783c2aa98e2SPeter Wemm char **dp; 784c2aa98e2SPeter Wemm char *mxmatch; 785c2aa98e2SPeter Wemm bool amatch; 78640266059SGregory Neil Shapiro bool gotmx = false; 787c2aa98e2SPeter Wemm int qtype; 788a7ec597cSGregory Neil Shapiro int initial; 789c2aa98e2SPeter Wemm int loopcnt; 79040266059SGregory Neil Shapiro char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)]; 791c2aa98e2SPeter Wemm char *searchlist[MAXDNSRCH + 2]; 792c2aa98e2SPeter Wemm 793c2aa98e2SPeter Wemm if (tTd(8, 2)) 79440266059SGregory Neil Shapiro sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx); 795c2aa98e2SPeter Wemm 796c2aa98e2SPeter Wemm if ((_res.options & RES_INIT) == 0 && res_init() == -1) 797c2aa98e2SPeter Wemm { 798c2aa98e2SPeter Wemm *statp = EX_UNAVAILABLE; 79940266059SGregory Neil Shapiro return false; 800c2aa98e2SPeter Wemm } 801c2aa98e2SPeter Wemm 802193538b7SGregory Neil Shapiro *statp = EX_OK; 803193538b7SGregory Neil Shapiro 804c2aa98e2SPeter Wemm /* 805c2aa98e2SPeter Wemm ** Initialize domain search list. If there is at least one 806c2aa98e2SPeter Wemm ** dot in the name, search the unmodified name first so we 807c2aa98e2SPeter Wemm ** find "vse.CS" in Czechoslovakia instead of in the local 80806f25ae9SGregory Neil Shapiro ** domain (e.g., vse.CS.Berkeley.EDU). Note that there is no 80906f25ae9SGregory Neil Shapiro ** longer a country named Czechoslovakia but this type of problem 81006f25ae9SGregory Neil Shapiro ** is still present. 811c2aa98e2SPeter Wemm ** 812c2aa98e2SPeter Wemm ** Older versions of the resolver could create this 813c2aa98e2SPeter Wemm ** list by tearing apart the host name. 814c2aa98e2SPeter Wemm */ 815c2aa98e2SPeter Wemm 816c2aa98e2SPeter Wemm loopcnt = 0; 817c2aa98e2SPeter Wemm cnameloop: 818c2aa98e2SPeter Wemm /* Check for dots in the name */ 819c2aa98e2SPeter Wemm for (cp = host, n = 0; *cp != '\0'; cp++) 820c2aa98e2SPeter Wemm if (*cp == '.') 821c2aa98e2SPeter Wemm n++; 822c2aa98e2SPeter Wemm 823c2aa98e2SPeter Wemm /* 824c2aa98e2SPeter Wemm ** Build the search list. 825c2aa98e2SPeter Wemm ** If there is at least one dot in name, start with a null 826c2aa98e2SPeter Wemm ** domain to search the unmodified name first. 827c2aa98e2SPeter Wemm ** If name does not end with a dot and search up local domain 828c2aa98e2SPeter Wemm ** tree desired, append each local domain component to the 829c2aa98e2SPeter Wemm ** search list; if name contains no dots and default domain 830c2aa98e2SPeter Wemm ** name is desired, append default domain name to search list; 831c2aa98e2SPeter Wemm ** else if name ends in a dot, remove that dot. 832c2aa98e2SPeter Wemm */ 833c2aa98e2SPeter Wemm 834c2aa98e2SPeter Wemm dp = searchlist; 835c2aa98e2SPeter Wemm if (n > 0) 836c2aa98e2SPeter Wemm *dp++ = ""; 837c2aa98e2SPeter Wemm if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options)) 838c2aa98e2SPeter Wemm { 83906f25ae9SGregory Neil Shapiro /* make sure there are less than MAXDNSRCH domains */ 84006f25ae9SGregory Neil Shapiro for (domain = RES_DNSRCH_VARIABLE, ret = 0; 84106f25ae9SGregory Neil Shapiro *domain != NULL && ret < MAXDNSRCH; 84206f25ae9SGregory Neil Shapiro ret++) 843c2aa98e2SPeter Wemm *dp++ = *domain++; 844c2aa98e2SPeter Wemm } 845c2aa98e2SPeter Wemm else if (n == 0 && bitset(RES_DEFNAMES, _res.options)) 846c2aa98e2SPeter Wemm { 847c2aa98e2SPeter Wemm *dp++ = _res.defdname; 848c2aa98e2SPeter Wemm } 849c2aa98e2SPeter Wemm else if (*cp == '.') 850c2aa98e2SPeter Wemm { 851c2aa98e2SPeter Wemm *cp = '\0'; 852c2aa98e2SPeter Wemm } 853c2aa98e2SPeter Wemm *dp = NULL; 854c2aa98e2SPeter Wemm 855c2aa98e2SPeter Wemm /* 856c2aa98e2SPeter Wemm ** Now loop through the search list, appending each domain in turn 857c2aa98e2SPeter Wemm ** name and searching for a match. 858c2aa98e2SPeter Wemm */ 859c2aa98e2SPeter Wemm 860c2aa98e2SPeter Wemm mxmatch = NULL; 861a7ec597cSGregory Neil Shapiro initial = T_A; 862a7ec597cSGregory Neil Shapiro # if NETINET6 863a7ec597cSGregory Neil Shapiro if (InetMode == AF_INET6) 864a7ec597cSGregory Neil Shapiro initial = T_AAAA; 865a7ec597cSGregory Neil Shapiro # endif /* NETINET6 */ 866a7ec597cSGregory Neil Shapiro qtype = initial; 867c2aa98e2SPeter Wemm 868c2aa98e2SPeter Wemm for (dp = searchlist; *dp != NULL; ) 869c2aa98e2SPeter Wemm { 870a7ec597cSGregory Neil Shapiro if (qtype == initial) 87140266059SGregory Neil Shapiro gotmx = false; 872c2aa98e2SPeter Wemm if (tTd(8, 5)) 87340266059SGregory Neil Shapiro sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n", 874c2aa98e2SPeter Wemm host, *dp, 87506f25ae9SGregory Neil Shapiro # if NETINET6 87606f25ae9SGregory Neil Shapiro qtype == T_AAAA ? "AAAA" : 87706f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 87806f25ae9SGregory Neil Shapiro qtype == T_A ? "A" : 87906f25ae9SGregory Neil Shapiro qtype == T_MX ? "MX" : 88006f25ae9SGregory Neil Shapiro "???"); 881193538b7SGregory Neil Shapiro errno = 0; 882c2aa98e2SPeter Wemm ret = res_querydomain(host, *dp, C_IN, qtype, 883c2aa98e2SPeter Wemm answer.qb2, sizeof(answer.qb2)); 884c2aa98e2SPeter Wemm if (ret <= 0) 885c2aa98e2SPeter Wemm { 88640266059SGregory Neil Shapiro int save_errno = errno; 887c2aa98e2SPeter Wemm 88840266059SGregory Neil Shapiro if (tTd(8, 7)) 88940266059SGregory Neil Shapiro sm_dprintf("\tNO: errno=%d, h_errno=%d\n", 89040266059SGregory Neil Shapiro save_errno, h_errno); 89140266059SGregory Neil Shapiro 89240266059SGregory Neil Shapiro if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN) 893c2aa98e2SPeter Wemm { 894193538b7SGregory Neil Shapiro /* 89540266059SGregory Neil Shapiro ** the name server seems to be down or broken. 896193538b7SGregory Neil Shapiro */ 897193538b7SGregory Neil Shapiro 898602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(TRY_AGAIN); 899605302a5SGregory Neil Shapiro if (**dp == '\0') 900605302a5SGregory Neil Shapiro { 901605302a5SGregory Neil Shapiro if (*statp == EX_OK) 902605302a5SGregory Neil Shapiro *statp = EX_TEMPFAIL; 903605302a5SGregory Neil Shapiro goto nexttype; 904605302a5SGregory Neil Shapiro } 905c2aa98e2SPeter Wemm *statp = EX_TEMPFAIL; 90606f25ae9SGregory Neil Shapiro 907602a2b1bSGregory Neil Shapiro if (WorkAroundBrokenAAAA) 908602a2b1bSGregory Neil Shapiro { 909193538b7SGregory Neil Shapiro /* 910193538b7SGregory Neil Shapiro ** Only return if not TRY_AGAIN as an 911193538b7SGregory Neil Shapiro ** attempt with a different qtype may 912193538b7SGregory Neil Shapiro ** succeed (res_querydomain() calls 913193538b7SGregory Neil Shapiro ** res_query() calls res_send() which 914193538b7SGregory Neil Shapiro ** sets errno to ETIMEDOUT if the 915193538b7SGregory Neil Shapiro ** nameservers could be contacted but 916193538b7SGregory Neil Shapiro ** didn't give an answer). 917193538b7SGregory Neil Shapiro */ 918193538b7SGregory Neil Shapiro 91940266059SGregory Neil Shapiro if (save_errno != ETIMEDOUT) 92040266059SGregory Neil Shapiro return false; 921602a2b1bSGregory Neil Shapiro } 92240266059SGregory Neil Shapiro else 92340266059SGregory Neil Shapiro return false; 924c2aa98e2SPeter Wemm } 925c2aa98e2SPeter Wemm 926605302a5SGregory Neil Shapiro nexttype: 927c2aa98e2SPeter Wemm if (h_errno != HOST_NOT_FOUND) 928c2aa98e2SPeter Wemm { 929c2aa98e2SPeter Wemm /* might have another type of interest */ 93006f25ae9SGregory Neil Shapiro # if NETINET6 93140266059SGregory Neil Shapiro if (qtype == T_AAAA) 93206f25ae9SGregory Neil Shapiro { 933c2aa98e2SPeter Wemm qtype = T_A; 934c2aa98e2SPeter Wemm continue; 935c2aa98e2SPeter Wemm } 93640266059SGregory Neil Shapiro else 93706f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 93840266059SGregory Neil Shapiro if (qtype == T_A && !gotmx && 93906f25ae9SGregory Neil Shapiro (trymx || **dp == '\0')) 940c2aa98e2SPeter Wemm { 941c2aa98e2SPeter Wemm qtype = T_MX; 942c2aa98e2SPeter Wemm continue; 943c2aa98e2SPeter Wemm } 944c2aa98e2SPeter Wemm } 945c2aa98e2SPeter Wemm 946c2aa98e2SPeter Wemm /* definite no -- try the next domain */ 947c2aa98e2SPeter Wemm dp++; 948a7ec597cSGregory Neil Shapiro qtype = initial; 949c2aa98e2SPeter Wemm continue; 950c2aa98e2SPeter Wemm } 951c2aa98e2SPeter Wemm else if (tTd(8, 7)) 95240266059SGregory Neil Shapiro sm_dprintf("\tYES\n"); 953c2aa98e2SPeter Wemm 954c2aa98e2SPeter Wemm /* avoid problems after truncation in tcp packets */ 955c2aa98e2SPeter Wemm if (ret > sizeof(answer)) 956c2aa98e2SPeter Wemm ret = sizeof(answer); 957af9557fdSGregory Neil Shapiro SM_ASSERT(ret >= 0); 958c2aa98e2SPeter Wemm 959c2aa98e2SPeter Wemm /* 960c2aa98e2SPeter Wemm ** Appear to have a match. Confirm it by searching for A or 961c2aa98e2SPeter Wemm ** CNAME records. If we don't have a local domain 962c2aa98e2SPeter Wemm ** wild card MX record, we will accept MX as well. 963c2aa98e2SPeter Wemm */ 964c2aa98e2SPeter Wemm 965c2aa98e2SPeter Wemm hp = (HEADER *) &answer; 96640266059SGregory Neil Shapiro ap = (unsigned char *) &answer + HFIXEDSZ; 96740266059SGregory Neil Shapiro eom = (unsigned char *) &answer + ret; 968c2aa98e2SPeter Wemm 969c2aa98e2SPeter Wemm /* skip question part of response -- we know what we asked */ 97040266059SGregory Neil Shapiro for (qdcount = ntohs((unsigned short) hp->qdcount); 97106f25ae9SGregory Neil Shapiro qdcount--; 97206f25ae9SGregory Neil Shapiro ap += ret + QFIXEDSZ) 973c2aa98e2SPeter Wemm { 974c2aa98e2SPeter Wemm if ((ret = dn_skipname(ap, eom)) < 0) 975c2aa98e2SPeter Wemm { 976c2aa98e2SPeter Wemm if (tTd(8, 20)) 97740266059SGregory Neil Shapiro sm_dprintf("qdcount failure (%d)\n", 97840266059SGregory Neil Shapiro ntohs((unsigned short) hp->qdcount)); 979c2aa98e2SPeter Wemm *statp = EX_SOFTWARE; 98040266059SGregory Neil Shapiro return false; /* ???XXX??? */ 981c2aa98e2SPeter Wemm } 982c2aa98e2SPeter Wemm } 983c2aa98e2SPeter Wemm 98440266059SGregory Neil Shapiro amatch = false; 98540266059SGregory Neil Shapiro for (ancount = ntohs((unsigned short) hp->ancount); 98606f25ae9SGregory Neil Shapiro --ancount >= 0 && ap < eom; 987c2aa98e2SPeter Wemm ap += n) 988c2aa98e2SPeter Wemm { 98940266059SGregory Neil Shapiro n = dn_expand((unsigned char *) &answer, eom, ap, 990d0cef73dSGregory Neil Shapiro (RES_UNC_T) nbuf, sizeof(nbuf)); 991c2aa98e2SPeter Wemm if (n < 0) 992c2aa98e2SPeter Wemm break; 993c2aa98e2SPeter Wemm ap += n; 994c2aa98e2SPeter Wemm GETSHORT(type, ap); 99540266059SGregory Neil Shapiro ap += INT16SZ; /* skip over class */ 99640266059SGregory Neil Shapiro GETLONG(ttl, ap); 99740266059SGregory Neil Shapiro GETSHORT(n, ap); /* rdlength */ 998c2aa98e2SPeter Wemm switch (type) 999c2aa98e2SPeter Wemm { 1000c2aa98e2SPeter Wemm case T_MX: 100140266059SGregory Neil Shapiro gotmx = true; 1002c2aa98e2SPeter Wemm if (**dp != '\0' && HasWildcardMX) 1003c2aa98e2SPeter Wemm { 1004c2aa98e2SPeter Wemm /* 1005c2aa98e2SPeter Wemm ** If we are using MX matches and have 1006c2aa98e2SPeter Wemm ** not yet gotten one, save this one 1007c2aa98e2SPeter Wemm ** but keep searching for an A or 1008c2aa98e2SPeter Wemm ** CNAME match. 1009c2aa98e2SPeter Wemm */ 1010c2aa98e2SPeter Wemm 1011c2aa98e2SPeter Wemm if (trymx && mxmatch == NULL) 1012c2aa98e2SPeter Wemm mxmatch = *dp; 1013c2aa98e2SPeter Wemm continue; 1014c2aa98e2SPeter Wemm } 1015c2aa98e2SPeter Wemm 1016c2aa98e2SPeter Wemm /* 1017c2aa98e2SPeter Wemm ** If we did not append a domain name, this 1018c2aa98e2SPeter Wemm ** must have been a canonical name to start 1019c2aa98e2SPeter Wemm ** with. Even if we did append a domain name, 1020c2aa98e2SPeter Wemm ** in the absence of a wildcard MX this must 1021c2aa98e2SPeter Wemm ** still be a real MX match. 1022c2aa98e2SPeter Wemm ** Such MX matches are as good as an A match, 1023c2aa98e2SPeter Wemm ** fall through. 1024c2aa98e2SPeter Wemm */ 102506f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 102606f25ae9SGregory Neil Shapiro 102706f25ae9SGregory Neil Shapiro # if NETINET6 102806f25ae9SGregory Neil Shapiro case T_AAAA: 102906f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 1030c2aa98e2SPeter Wemm case T_A: 1031c2aa98e2SPeter Wemm /* Flag that a good match was found */ 103240266059SGregory Neil Shapiro amatch = true; 1033c2aa98e2SPeter Wemm 1034c2aa98e2SPeter Wemm /* continue in case a CNAME also exists */ 1035c2aa98e2SPeter Wemm continue; 1036c2aa98e2SPeter Wemm 1037c2aa98e2SPeter Wemm case T_CNAME: 1038c2aa98e2SPeter Wemm if (DontExpandCnames) 1039c2aa98e2SPeter Wemm { 1040c2aa98e2SPeter Wemm /* got CNAME -- guaranteed canonical */ 104140266059SGregory Neil Shapiro amatch = true; 1042c2aa98e2SPeter Wemm break; 1043c2aa98e2SPeter Wemm } 1044c2aa98e2SPeter Wemm 1045c2aa98e2SPeter Wemm if (loopcnt++ > MAXCNAMEDEPTH) 1046c2aa98e2SPeter Wemm { 1047c2aa98e2SPeter Wemm /*XXX should notify postmaster XXX*/ 1048c2aa98e2SPeter Wemm message("DNS failure: CNAME loop for %s", 1049c2aa98e2SPeter Wemm host); 1050c2aa98e2SPeter Wemm if (CurEnv->e_message == NULL) 1051c2aa98e2SPeter Wemm { 1052c2aa98e2SPeter Wemm char ebuf[MAXLINE]; 1053c2aa98e2SPeter Wemm 105440266059SGregory Neil Shapiro (void) sm_snprintf(ebuf, 1055d0cef73dSGregory Neil Shapiro sizeof(ebuf), 1056c2aa98e2SPeter Wemm "Deferred: DNS failure: CNAME loop for %.100s", 1057c2aa98e2SPeter Wemm host); 105840266059SGregory Neil Shapiro CurEnv->e_message = 105940266059SGregory Neil Shapiro sm_rpool_strdup_x( 106040266059SGregory Neil Shapiro CurEnv->e_rpool, ebuf); 1061c2aa98e2SPeter Wemm } 1062602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(NO_RECOVERY); 1063c2aa98e2SPeter Wemm *statp = EX_CONFIG; 106440266059SGregory Neil Shapiro return false; 1065c2aa98e2SPeter Wemm } 1066c2aa98e2SPeter Wemm 1067c2aa98e2SPeter Wemm /* value points at name */ 106840266059SGregory Neil Shapiro if ((ret = dn_expand((unsigned char *)&answer, 106940266059SGregory Neil Shapiro eom, ap, (RES_UNC_T) nbuf, 107040266059SGregory Neil Shapiro sizeof(nbuf))) < 0) 1071c2aa98e2SPeter Wemm break; 107240266059SGregory Neil Shapiro (void) sm_strlcpy(host, nbuf, hbsize); 1073c2aa98e2SPeter Wemm 1074c2aa98e2SPeter Wemm /* 1075c2aa98e2SPeter Wemm ** RFC 1034 section 3.6 specifies that CNAME 1076c2aa98e2SPeter Wemm ** should point at the canonical name -- but 1077c2aa98e2SPeter Wemm ** urges software to try again anyway. 1078c2aa98e2SPeter Wemm */ 1079c2aa98e2SPeter Wemm 1080c2aa98e2SPeter Wemm goto cnameloop; 1081c2aa98e2SPeter Wemm 1082c2aa98e2SPeter Wemm default: 1083c2aa98e2SPeter Wemm /* not a record of interest */ 1084c2aa98e2SPeter Wemm continue; 1085c2aa98e2SPeter Wemm } 1086c2aa98e2SPeter Wemm } 1087c2aa98e2SPeter Wemm 1088c2aa98e2SPeter Wemm if (amatch) 1089c2aa98e2SPeter Wemm { 1090c2aa98e2SPeter Wemm /* 1091c2aa98e2SPeter Wemm ** Got a good match -- either an A, CNAME, or an 1092c2aa98e2SPeter Wemm ** exact MX record. Save it and get out of here. 1093c2aa98e2SPeter Wemm */ 1094c2aa98e2SPeter Wemm 1095c2aa98e2SPeter Wemm mxmatch = *dp; 1096c2aa98e2SPeter Wemm break; 1097c2aa98e2SPeter Wemm } 1098c2aa98e2SPeter Wemm 1099c2aa98e2SPeter Wemm /* 1100c2aa98e2SPeter Wemm ** Nothing definitive yet. 1101c2aa98e2SPeter Wemm ** If this was a T_A query and we haven't yet found a MX 1102c2aa98e2SPeter Wemm ** match, try T_MX if allowed to do so. 1103c2aa98e2SPeter Wemm ** Otherwise, try the next domain. 1104c2aa98e2SPeter Wemm */ 1105c2aa98e2SPeter Wemm 110606f25ae9SGregory Neil Shapiro # if NETINET6 110740266059SGregory Neil Shapiro if (qtype == T_AAAA) 1108c2aa98e2SPeter Wemm qtype = T_A; 110940266059SGregory Neil Shapiro else 111006f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 111140266059SGregory Neil Shapiro if (qtype == T_A && !gotmx && (trymx || **dp == '\0')) 1112c2aa98e2SPeter Wemm qtype = T_MX; 1113c2aa98e2SPeter Wemm else 1114c2aa98e2SPeter Wemm { 1115a7ec597cSGregory Neil Shapiro qtype = initial; 1116c2aa98e2SPeter Wemm dp++; 1117c2aa98e2SPeter Wemm } 1118c2aa98e2SPeter Wemm } 1119c2aa98e2SPeter Wemm 1120c2aa98e2SPeter Wemm /* if nothing was found, we are done */ 1121c2aa98e2SPeter Wemm if (mxmatch == NULL) 1122c2aa98e2SPeter Wemm { 1123193538b7SGregory Neil Shapiro if (*statp == EX_OK) 1124c2aa98e2SPeter Wemm *statp = EX_NOHOST; 112540266059SGregory Neil Shapiro return false; 1126c2aa98e2SPeter Wemm } 1127c2aa98e2SPeter Wemm 1128c2aa98e2SPeter Wemm /* 1129c2aa98e2SPeter Wemm ** Create canonical name and return. 1130c2aa98e2SPeter Wemm ** If saved domain name is null, name was already canonical. 1131c2aa98e2SPeter Wemm ** Otherwise append the saved domain name. 1132c2aa98e2SPeter Wemm */ 1133c2aa98e2SPeter Wemm 1134d0cef73dSGregory Neil Shapiro (void) sm_snprintf(nbuf, sizeof(nbuf), "%.*s%s%.*s", MAXDNAME, host, 1135c2aa98e2SPeter Wemm *mxmatch == '\0' ? "" : ".", 1136c2aa98e2SPeter Wemm MAXDNAME, mxmatch); 113740266059SGregory Neil Shapiro (void) sm_strlcpy(host, nbuf, hbsize); 1138c2aa98e2SPeter Wemm if (tTd(8, 5)) 113940266059SGregory Neil Shapiro sm_dprintf("dns_getcanonname: %s\n", host); 1140c2aa98e2SPeter Wemm *statp = EX_OK; 114140266059SGregory Neil Shapiro 114240266059SGregory Neil Shapiro /* return only one TTL entry, that should be sufficient */ 114340266059SGregory Neil Shapiro if (ttl > 0 && pttl != NULL) 114440266059SGregory Neil Shapiro *pttl = ttl; 114540266059SGregory Neil Shapiro return true; 1146c2aa98e2SPeter Wemm } 1147c2aa98e2SPeter Wemm #endif /* NAMED_BIND */ 1148