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 #ifndef lint 17c2aa98e2SPeter Wemm # if NAMED_BIND 18602a2b1bSGregory Neil Shapiro static char id[] = "@(#)$Id: domain.c,v 8.114.6.1.2.8 2001/02/12 21:40:19 gshapiro Exp $ (with name server)"; 1906f25ae9SGregory Neil Shapiro # else /* NAMED_BIND */ 20602a2b1bSGregory Neil Shapiro static char id[] = "@(#)$Id: domain.c,v 8.114.6.1.2.8 2001/02/12 21:40:19 gshapiro Exp $ (without name server)"; 2106f25ae9SGregory Neil Shapiro # endif /* NAMED_BIND */ 2206f25ae9SGregory Neil Shapiro #endif /* ! lint */ 2306f25ae9SGregory Neil Shapiro 24c2aa98e2SPeter Wemm 25c2aa98e2SPeter Wemm #if NAMED_BIND 26c2aa98e2SPeter Wemm 27c2aa98e2SPeter Wemm # include <arpa/inet.h> 28c2aa98e2SPeter Wemm 29c2aa98e2SPeter Wemm /* 30c2aa98e2SPeter Wemm ** The standard udp packet size PACKETSZ (512) is not sufficient for some 31c2aa98e2SPeter Wemm ** nameserver answers containing very many resource records. The resolver 32c2aa98e2SPeter Wemm ** may switch to tcp and retry if it detects udp packet overflow. 33c2aa98e2SPeter Wemm ** Also note that the resolver routines res_query and res_search return 34c2aa98e2SPeter Wemm ** the size of the *un*truncated answer in case the supplied answer buffer 35c2aa98e2SPeter Wemm ** it not big enough to accommodate the entire answer. 36c2aa98e2SPeter Wemm */ 37c2aa98e2SPeter Wemm 38c2aa98e2SPeter Wemm # ifndef MAXPACKET 39c2aa98e2SPeter Wemm # define MAXPACKET 8192 /* max packet size used internally by BIND */ 4006f25ae9SGregory Neil Shapiro # endif /* ! MAXPACKET */ 41c2aa98e2SPeter Wemm 42c2aa98e2SPeter Wemm typedef union 43c2aa98e2SPeter Wemm { 44c2aa98e2SPeter Wemm HEADER qb1; 45c2aa98e2SPeter Wemm u_char qb2[MAXPACKET]; 46c2aa98e2SPeter Wemm } querybuf; 47c2aa98e2SPeter Wemm 48c2aa98e2SPeter Wemm # ifndef MXHOSTBUFSIZE 49c2aa98e2SPeter Wemm # define MXHOSTBUFSIZE (128 * MAXMXHOSTS) 5006f25ae9SGregory Neil Shapiro # endif /* ! MXHOSTBUFSIZE */ 51c2aa98e2SPeter Wemm 52c2aa98e2SPeter Wemm static char MXHostBuf[MXHOSTBUFSIZE]; 53c2aa98e2SPeter Wemm 54c2aa98e2SPeter Wemm # ifndef MAXDNSRCH 55c2aa98e2SPeter Wemm # define MAXDNSRCH 6 /* number of possible domains to search */ 5606f25ae9SGregory Neil Shapiro # endif /* ! MAXDNSRCH */ 5706f25ae9SGregory Neil Shapiro 5806f25ae9SGregory Neil Shapiro # ifndef RES_DNSRCH_VARIABLE 5906f25ae9SGregory Neil Shapiro # define RES_DNSRCH_VARIABLE _res.dnsrch 6006f25ae9SGregory Neil Shapiro # endif /* ! RES_DNSRCH_VARIABLE */ 61c2aa98e2SPeter Wemm 62c2aa98e2SPeter Wemm # ifndef MAX 63c2aa98e2SPeter Wemm # define MAX(a, b) ((a) > (b) ? (a) : (b)) 6406f25ae9SGregory Neil Shapiro # endif /* ! MAX */ 65c2aa98e2SPeter Wemm 66c2aa98e2SPeter Wemm # ifndef NO_DATA 67c2aa98e2SPeter Wemm # define NO_DATA NO_ADDRESS 6806f25ae9SGregory Neil Shapiro # endif /* ! NO_DATA */ 69c2aa98e2SPeter Wemm 70c2aa98e2SPeter Wemm # ifndef HFIXEDSZ 71c2aa98e2SPeter Wemm # define HFIXEDSZ 12 /* sizeof(HEADER) */ 7206f25ae9SGregory Neil Shapiro # endif /* ! HFIXEDSZ */ 73c2aa98e2SPeter Wemm 74c2aa98e2SPeter Wemm # define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */ 75c2aa98e2SPeter Wemm 76c2aa98e2SPeter Wemm # if defined(__RES) && (__RES >= 19940415) 77c2aa98e2SPeter Wemm # define RES_UNC_T char * 7806f25ae9SGregory Neil Shapiro # else /* defined(__RES) && (__RES >= 19940415) */ 79c2aa98e2SPeter Wemm # define RES_UNC_T u_char * 8006f25ae9SGregory Neil Shapiro # endif /* defined(__RES) && (__RES >= 19940415) */ 8106f25ae9SGregory Neil Shapiro 8206f25ae9SGregory Neil Shapiro static char *gethostalias __P((char *)); 8306f25ae9SGregory Neil Shapiro static int mxrand __P((char *)); 8406f25ae9SGregory Neil Shapiro 85c2aa98e2SPeter Wemm /* 86c2aa98e2SPeter Wemm ** GETMXRR -- get MX resource records for a domain 87c2aa98e2SPeter Wemm ** 88c2aa98e2SPeter Wemm ** Parameters: 89c2aa98e2SPeter Wemm ** host -- the name of the host to MX. 90c2aa98e2SPeter Wemm ** mxhosts -- a pointer to a return buffer of MX records. 9106f25ae9SGregory Neil Shapiro ** mxprefs -- a pointer to a return buffer of MX preferences. 9206f25ae9SGregory Neil Shapiro ** If NULL, don't try to populate. 93c2aa98e2SPeter Wemm ** droplocalhost -- If TRUE, all MX records less preferred 94c2aa98e2SPeter Wemm ** than the local host (as determined by $=w) will 95c2aa98e2SPeter Wemm ** be discarded. 96c2aa98e2SPeter Wemm ** rcode -- a pointer to an EX_ status code. 97c2aa98e2SPeter Wemm ** 98c2aa98e2SPeter Wemm ** Returns: 99c2aa98e2SPeter Wemm ** The number of MX records found. 100c2aa98e2SPeter Wemm ** -1 if there is an internal failure. 101c2aa98e2SPeter Wemm ** If no MX records are found, mxhosts[0] is set to host 102c2aa98e2SPeter Wemm ** and 1 is returned. 103c2aa98e2SPeter Wemm */ 104c2aa98e2SPeter Wemm 105c2aa98e2SPeter Wemm int 10606f25ae9SGregory Neil Shapiro getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode) 107c2aa98e2SPeter Wemm char *host; 108c2aa98e2SPeter Wemm char **mxhosts; 10906f25ae9SGregory Neil Shapiro u_short *mxprefs; 110c2aa98e2SPeter Wemm bool droplocalhost; 111c2aa98e2SPeter Wemm int *rcode; 112c2aa98e2SPeter Wemm { 113c2aa98e2SPeter Wemm register u_char *eom, *cp; 114c2aa98e2SPeter Wemm register int i, j, n; 115c2aa98e2SPeter Wemm int nmx = 0; 116c2aa98e2SPeter Wemm register char *bp; 117c2aa98e2SPeter Wemm HEADER *hp; 118c2aa98e2SPeter Wemm querybuf answer; 119c2aa98e2SPeter Wemm int ancount, qdcount, buflen; 120c2aa98e2SPeter Wemm bool seenlocal = FALSE; 121c2aa98e2SPeter Wemm u_short pref, type; 122c2aa98e2SPeter Wemm u_short localpref = 256; 123c2aa98e2SPeter Wemm char *fallbackMX = FallBackMX; 124c2aa98e2SPeter Wemm bool trycanon = FALSE; 12506f25ae9SGregory Neil Shapiro u_short *prefs; 126c2aa98e2SPeter Wemm int (*resfunc)(); 127c2aa98e2SPeter Wemm u_short prefer[MAXMXHOSTS]; 128c2aa98e2SPeter Wemm int weight[MAXMXHOSTS]; 12906f25ae9SGregory Neil Shapiro extern int res_query(), res_search(); 130c2aa98e2SPeter Wemm 131c2aa98e2SPeter Wemm if (tTd(8, 2)) 13206f25ae9SGregory Neil Shapiro dprintf("getmxrr(%s, droplocalhost=%d)\n", 13306f25ae9SGregory Neil Shapiro host, droplocalhost); 134c2aa98e2SPeter Wemm 135c2aa98e2SPeter Wemm if (fallbackMX != NULL && droplocalhost && 136c2aa98e2SPeter Wemm wordinclass(fallbackMX, 'w')) 137c2aa98e2SPeter Wemm { 138c2aa98e2SPeter Wemm /* don't use fallback for this pass */ 139c2aa98e2SPeter Wemm fallbackMX = NULL; 140c2aa98e2SPeter Wemm } 141c2aa98e2SPeter Wemm 142c2aa98e2SPeter Wemm *rcode = EX_OK; 143c2aa98e2SPeter Wemm 14406f25ae9SGregory Neil Shapiro if (mxprefs != NULL) 14506f25ae9SGregory Neil Shapiro prefs = mxprefs; 14606f25ae9SGregory Neil Shapiro else 14706f25ae9SGregory Neil Shapiro prefs = prefer; 14806f25ae9SGregory Neil Shapiro 14906f25ae9SGregory Neil Shapiro 150c2aa98e2SPeter Wemm /* efficiency hack -- numeric or non-MX lookups */ 151c2aa98e2SPeter Wemm if (host[0] == '[') 152c2aa98e2SPeter Wemm goto punt; 153c2aa98e2SPeter Wemm 154c2aa98e2SPeter Wemm /* 155c2aa98e2SPeter Wemm ** If we don't have MX records in our host switch, don't 156c2aa98e2SPeter Wemm ** try for MX records. Note that this really isn't "right", 157c2aa98e2SPeter Wemm ** since we might be set up to try NIS first and then DNS; 158c2aa98e2SPeter Wemm ** if the host is found in NIS we really shouldn't be doing 159c2aa98e2SPeter Wemm ** MX lookups. However, that should be a degenerate case. 160c2aa98e2SPeter Wemm */ 161c2aa98e2SPeter Wemm 162c2aa98e2SPeter Wemm if (!UseNameServer) 163c2aa98e2SPeter Wemm goto punt; 164c2aa98e2SPeter Wemm if (HasWildcardMX && ConfigLevel >= 6) 165c2aa98e2SPeter Wemm resfunc = res_query; 166c2aa98e2SPeter Wemm else 167c2aa98e2SPeter Wemm resfunc = res_search; 168c2aa98e2SPeter Wemm 169c2aa98e2SPeter Wemm errno = 0; 170c2aa98e2SPeter Wemm n = (*resfunc)(host, C_IN, T_MX, (u_char *) &answer, sizeof(answer)); 171c2aa98e2SPeter Wemm if (n < 0) 172c2aa98e2SPeter Wemm { 173c2aa98e2SPeter Wemm if (tTd(8, 1)) 17406f25ae9SGregory Neil Shapiro dprintf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n", 175c2aa98e2SPeter Wemm (host == NULL) ? "<NULL>" : host, errno, h_errno); 176c2aa98e2SPeter Wemm switch (h_errno) 177c2aa98e2SPeter Wemm { 178c2aa98e2SPeter Wemm case NO_DATA: 179c2aa98e2SPeter Wemm trycanon = TRUE; 18006f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 181c2aa98e2SPeter Wemm 182c2aa98e2SPeter Wemm case NO_RECOVERY: 183c2aa98e2SPeter Wemm /* no MX data on this host */ 184c2aa98e2SPeter Wemm goto punt; 185c2aa98e2SPeter Wemm 186c2aa98e2SPeter Wemm case HOST_NOT_FOUND: 187c2aa98e2SPeter Wemm # if BROKEN_RES_SEARCH 188c2aa98e2SPeter Wemm case 0: /* Ultrix resolver retns failure w/ h_errno=0 */ 18906f25ae9SGregory Neil Shapiro # endif /* BROKEN_RES_SEARCH */ 190c2aa98e2SPeter Wemm /* host doesn't exist in DNS; might be in /etc/hosts */ 191c2aa98e2SPeter Wemm trycanon = TRUE; 192c2aa98e2SPeter Wemm *rcode = EX_NOHOST; 193c2aa98e2SPeter Wemm goto punt; 194c2aa98e2SPeter Wemm 195c2aa98e2SPeter Wemm case TRY_AGAIN: 196c2aa98e2SPeter Wemm case -1: 197c2aa98e2SPeter Wemm /* couldn't connect to the name server */ 198c2aa98e2SPeter Wemm if (fallbackMX != NULL) 199c2aa98e2SPeter Wemm { 200c2aa98e2SPeter Wemm /* name server is hosed -- push to fallback */ 20106f25ae9SGregory Neil Shapiro if (nmx > 0) 20206f25ae9SGregory Neil Shapiro prefs[nmx] = prefs[nmx - 1] + 1; 20306f25ae9SGregory Neil Shapiro else 20406f25ae9SGregory Neil Shapiro prefs[nmx] = 0; 205c2aa98e2SPeter Wemm mxhosts[nmx++] = fallbackMX; 206c2aa98e2SPeter Wemm return nmx; 207c2aa98e2SPeter Wemm } 208c2aa98e2SPeter Wemm /* it might come up later; better queue it up */ 209c2aa98e2SPeter Wemm *rcode = EX_TEMPFAIL; 210c2aa98e2SPeter Wemm break; 211c2aa98e2SPeter Wemm 212c2aa98e2SPeter Wemm default: 213c2aa98e2SPeter Wemm syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)\n", 214c2aa98e2SPeter Wemm host, h_errno); 215c2aa98e2SPeter Wemm *rcode = EX_OSERR; 216c2aa98e2SPeter Wemm break; 217c2aa98e2SPeter Wemm } 218c2aa98e2SPeter Wemm 219c2aa98e2SPeter Wemm /* irreconcilable differences */ 22006f25ae9SGregory Neil Shapiro return -1; 221c2aa98e2SPeter Wemm } 222c2aa98e2SPeter Wemm 223c2aa98e2SPeter Wemm /* avoid problems after truncation in tcp packets */ 224c2aa98e2SPeter Wemm if (n > sizeof(answer)) 225c2aa98e2SPeter Wemm n = sizeof(answer); 226c2aa98e2SPeter Wemm 227c2aa98e2SPeter Wemm /* find first satisfactory answer */ 228c2aa98e2SPeter Wemm hp = (HEADER *)&answer; 229c2aa98e2SPeter Wemm cp = (u_char *)&answer + HFIXEDSZ; 230c2aa98e2SPeter Wemm eom = (u_char *)&answer + n; 23106f25ae9SGregory Neil Shapiro for (qdcount = ntohs((u_short)hp->qdcount); 23206f25ae9SGregory Neil Shapiro qdcount--; 23306f25ae9SGregory Neil Shapiro cp += n + QFIXEDSZ) 23406f25ae9SGregory Neil Shapiro { 235c2aa98e2SPeter Wemm if ((n = dn_skipname(cp, eom)) < 0) 236c2aa98e2SPeter Wemm goto punt; 23706f25ae9SGregory Neil Shapiro } 238c2aa98e2SPeter Wemm buflen = sizeof(MXHostBuf) - 1; 239c2aa98e2SPeter Wemm bp = MXHostBuf; 24006f25ae9SGregory Neil Shapiro ancount = ntohs((u_short)hp->ancount); 241c2aa98e2SPeter Wemm while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1) 242c2aa98e2SPeter Wemm { 243c2aa98e2SPeter Wemm if ((n = dn_expand((u_char *)&answer, 244c2aa98e2SPeter Wemm eom, cp, (RES_UNC_T) bp, buflen)) < 0) 245c2aa98e2SPeter Wemm break; 246c2aa98e2SPeter Wemm cp += n; 247c2aa98e2SPeter Wemm GETSHORT(type, cp); 248c2aa98e2SPeter Wemm cp += INT16SZ + INT32SZ; 249c2aa98e2SPeter Wemm GETSHORT(n, cp); 250c2aa98e2SPeter Wemm if (type != T_MX) 251c2aa98e2SPeter Wemm { 252c2aa98e2SPeter Wemm if (tTd(8, 8) || _res.options & RES_DEBUG) 25306f25ae9SGregory Neil Shapiro dprintf("unexpected answer type %d, size %d\n", 254c2aa98e2SPeter Wemm type, n); 255c2aa98e2SPeter Wemm cp += n; 256c2aa98e2SPeter Wemm continue; 257c2aa98e2SPeter Wemm } 258c2aa98e2SPeter Wemm GETSHORT(pref, cp); 259c2aa98e2SPeter Wemm if ((n = dn_expand((u_char *)&answer, eom, cp, 260c2aa98e2SPeter Wemm (RES_UNC_T) bp, buflen)) < 0) 261c2aa98e2SPeter Wemm break; 262c2aa98e2SPeter Wemm cp += n; 263c2aa98e2SPeter Wemm if (wordinclass(bp, 'w')) 264c2aa98e2SPeter Wemm { 265c2aa98e2SPeter Wemm if (tTd(8, 3)) 26606f25ae9SGregory Neil Shapiro dprintf("found localhost (%s) in MX list, pref=%d\n", 267c2aa98e2SPeter Wemm bp, pref); 268c2aa98e2SPeter Wemm if (droplocalhost) 269c2aa98e2SPeter Wemm { 270c2aa98e2SPeter Wemm if (!seenlocal || pref < localpref) 271c2aa98e2SPeter Wemm localpref = pref; 272c2aa98e2SPeter Wemm seenlocal = TRUE; 273c2aa98e2SPeter Wemm continue; 274c2aa98e2SPeter Wemm } 275c2aa98e2SPeter Wemm weight[nmx] = 0; 276c2aa98e2SPeter Wemm } 277c2aa98e2SPeter Wemm else 278c2aa98e2SPeter Wemm weight[nmx] = mxrand(bp); 27906f25ae9SGregory Neil Shapiro prefs[nmx] = pref; 280c2aa98e2SPeter Wemm mxhosts[nmx++] = bp; 281c2aa98e2SPeter Wemm n = strlen(bp); 282c2aa98e2SPeter Wemm bp += n; 283c2aa98e2SPeter Wemm if (bp[-1] != '.') 284c2aa98e2SPeter Wemm { 285c2aa98e2SPeter Wemm *bp++ = '.'; 286c2aa98e2SPeter Wemm n++; 287c2aa98e2SPeter Wemm } 288c2aa98e2SPeter Wemm *bp++ = '\0'; 289c2aa98e2SPeter Wemm buflen -= n + 1; 290c2aa98e2SPeter Wemm } 291c2aa98e2SPeter Wemm 292c2aa98e2SPeter Wemm /* sort the records */ 293c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 294c2aa98e2SPeter Wemm { 295c2aa98e2SPeter Wemm for (j = i + 1; j < nmx; j++) 296c2aa98e2SPeter Wemm { 29706f25ae9SGregory Neil Shapiro if (prefs[i] > prefs[j] || 29806f25ae9SGregory Neil Shapiro (prefs[i] == prefs[j] && weight[i] > weight[j])) 299c2aa98e2SPeter Wemm { 300c2aa98e2SPeter Wemm register int temp; 301c2aa98e2SPeter Wemm register char *temp1; 302c2aa98e2SPeter Wemm 30306f25ae9SGregory Neil Shapiro temp = prefs[i]; 30406f25ae9SGregory Neil Shapiro prefs[i] = prefs[j]; 30506f25ae9SGregory Neil Shapiro prefs[j] = temp; 306c2aa98e2SPeter Wemm temp1 = mxhosts[i]; 307c2aa98e2SPeter Wemm mxhosts[i] = mxhosts[j]; 308c2aa98e2SPeter Wemm mxhosts[j] = temp1; 309c2aa98e2SPeter Wemm temp = weight[i]; 310c2aa98e2SPeter Wemm weight[i] = weight[j]; 311c2aa98e2SPeter Wemm weight[j] = temp; 312c2aa98e2SPeter Wemm } 313c2aa98e2SPeter Wemm } 31406f25ae9SGregory Neil Shapiro if (seenlocal && prefs[i] >= localpref) 315c2aa98e2SPeter Wemm { 316c2aa98e2SPeter Wemm /* truncate higher preference part of list */ 317c2aa98e2SPeter Wemm nmx = i; 318c2aa98e2SPeter Wemm } 319c2aa98e2SPeter Wemm } 320c2aa98e2SPeter Wemm 321c2aa98e2SPeter Wemm /* delete duplicates from list (yes, some bozos have duplicates) */ 322c2aa98e2SPeter Wemm for (i = 0; i < nmx - 1; ) 323c2aa98e2SPeter Wemm { 324c2aa98e2SPeter Wemm if (strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0) 325c2aa98e2SPeter Wemm i++; 326c2aa98e2SPeter Wemm else 327c2aa98e2SPeter Wemm { 328c2aa98e2SPeter Wemm /* compress out duplicate */ 329c2aa98e2SPeter Wemm for (j = i + 1; j < nmx; j++) 33006f25ae9SGregory Neil Shapiro { 331c2aa98e2SPeter Wemm mxhosts[j] = mxhosts[j + 1]; 33206f25ae9SGregory Neil Shapiro prefs[j] = prefs[j + 1]; 33306f25ae9SGregory Neil Shapiro } 334c2aa98e2SPeter Wemm nmx--; 335c2aa98e2SPeter Wemm } 336c2aa98e2SPeter Wemm } 337c2aa98e2SPeter Wemm 338c2aa98e2SPeter Wemm if (nmx == 0) 339c2aa98e2SPeter Wemm { 340c2aa98e2SPeter Wemm punt: 34106f25ae9SGregory Neil Shapiro if (seenlocal) 342c2aa98e2SPeter Wemm { 34306f25ae9SGregory Neil Shapiro struct hostent *h = NULL; 34406f25ae9SGregory Neil Shapiro 345c2aa98e2SPeter Wemm /* 346c2aa98e2SPeter Wemm ** If we have deleted all MX entries, this is 347c2aa98e2SPeter Wemm ** an error -- we should NEVER send to a host that 348c2aa98e2SPeter Wemm ** has an MX, and this should have been caught 349c2aa98e2SPeter Wemm ** earlier in the config file. 350c2aa98e2SPeter Wemm ** 351c2aa98e2SPeter Wemm ** Some sites prefer to go ahead and try the 352c2aa98e2SPeter Wemm ** A record anyway; that case is handled by 353c2aa98e2SPeter Wemm ** setting TryNullMXList. I believe this is a 354c2aa98e2SPeter Wemm ** bad idea, but it's up to you.... 355c2aa98e2SPeter Wemm */ 356c2aa98e2SPeter Wemm 35706f25ae9SGregory Neil Shapiro if (TryNullMXList) 35806f25ae9SGregory Neil Shapiro { 359602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 36006f25ae9SGregory Neil Shapiro errno = 0; 36106f25ae9SGregory Neil Shapiro h = sm_gethostbyname(host, AF_INET); 36206f25ae9SGregory Neil Shapiro if (h == NULL) 36306f25ae9SGregory Neil Shapiro { 36406f25ae9SGregory Neil Shapiro if (errno == ETIMEDOUT || 36506f25ae9SGregory Neil Shapiro h_errno == TRY_AGAIN || 36606f25ae9SGregory Neil Shapiro (errno == ECONNREFUSED && 36706f25ae9SGregory Neil Shapiro UseNameServer)) 36806f25ae9SGregory Neil Shapiro { 36906f25ae9SGregory Neil Shapiro *rcode = EX_TEMPFAIL; 37006f25ae9SGregory Neil Shapiro return -1; 37106f25ae9SGregory Neil Shapiro } 37206f25ae9SGregory Neil Shapiro # if NETINET6 373602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(0); 37406f25ae9SGregory Neil Shapiro errno = 0; 37506f25ae9SGregory Neil Shapiro h = sm_gethostbyname(host, AF_INET6); 37606f25ae9SGregory Neil Shapiro if (h == NULL && 37706f25ae9SGregory Neil Shapiro (errno == ETIMEDOUT || 37806f25ae9SGregory Neil Shapiro h_errno == TRY_AGAIN || 37906f25ae9SGregory Neil Shapiro (errno == ECONNREFUSED && 38006f25ae9SGregory Neil Shapiro UseNameServer))) 38106f25ae9SGregory Neil Shapiro { 38206f25ae9SGregory Neil Shapiro *rcode = EX_TEMPFAIL; 38306f25ae9SGregory Neil Shapiro return -1; 38406f25ae9SGregory Neil Shapiro } 38506f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 38606f25ae9SGregory Neil Shapiro } 38706f25ae9SGregory Neil Shapiro } 38806f25ae9SGregory Neil Shapiro 38906f25ae9SGregory Neil Shapiro if (h == NULL) 39006f25ae9SGregory Neil Shapiro { 391c2aa98e2SPeter Wemm *rcode = EX_CONFIG; 392c2aa98e2SPeter Wemm syserr("MX list for %s points back to %s", 393c2aa98e2SPeter Wemm host, MyHostName); 394c2aa98e2SPeter Wemm return -1; 395c2aa98e2SPeter Wemm } 396193538b7SGregory Neil Shapiro # if _FFR_FREEHOSTENT && NETINET6 397193538b7SGregory Neil Shapiro freehostent(h); 398193538b7SGregory Neil Shapiro hp = NULL; 399193538b7SGregory Neil Shapiro # endif /* _FFR_FREEHOSTENT && NETINET6 */ 40006f25ae9SGregory Neil Shapiro } 401c2aa98e2SPeter Wemm if (strlen(host) >= (SIZE_T) sizeof MXHostBuf) 402c2aa98e2SPeter Wemm { 403c2aa98e2SPeter Wemm *rcode = EX_CONFIG; 404c2aa98e2SPeter Wemm syserr("Host name %s too long", 405c2aa98e2SPeter Wemm shortenstring(host, MAXSHORTSTR)); 406c2aa98e2SPeter Wemm return -1; 407c2aa98e2SPeter Wemm } 408c2aa98e2SPeter Wemm snprintf(MXHostBuf, sizeof MXHostBuf, "%s", host); 409c2aa98e2SPeter Wemm mxhosts[0] = MXHostBuf; 41006f25ae9SGregory Neil Shapiro prefs[0] = 0; 411c2aa98e2SPeter Wemm if (host[0] == '[') 412c2aa98e2SPeter Wemm { 413c2aa98e2SPeter Wemm register char *p; 41406f25ae9SGregory Neil Shapiro # if NETINET6 41506f25ae9SGregory Neil Shapiro struct sockaddr_in6 tmp6; 41606f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 417c2aa98e2SPeter Wemm 418c2aa98e2SPeter Wemm /* this may be an MX suppression-style address */ 419c2aa98e2SPeter Wemm p = strchr(MXHostBuf, ']'); 420c2aa98e2SPeter Wemm if (p != NULL) 421c2aa98e2SPeter Wemm { 422c2aa98e2SPeter Wemm *p = '\0'; 42306f25ae9SGregory Neil Shapiro 424c2aa98e2SPeter Wemm if (inet_addr(&MXHostBuf[1]) != INADDR_NONE) 425c2aa98e2SPeter Wemm { 426c2aa98e2SPeter Wemm nmx++; 427c2aa98e2SPeter Wemm *p = ']'; 428c2aa98e2SPeter Wemm } 42906f25ae9SGregory Neil Shapiro # if NETINET6 43006f25ae9SGregory Neil Shapiro else if (inet_pton(AF_INET6, &MXHostBuf[1], 43106f25ae9SGregory Neil Shapiro &tmp6.sin6_addr) == 1) 43206f25ae9SGregory Neil Shapiro { 43306f25ae9SGregory Neil Shapiro nmx++; 43406f25ae9SGregory Neil Shapiro *p = ']'; 43506f25ae9SGregory Neil Shapiro } 43606f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 437c2aa98e2SPeter Wemm else 438c2aa98e2SPeter Wemm { 439c2aa98e2SPeter Wemm trycanon = TRUE; 440c2aa98e2SPeter Wemm mxhosts[0]++; 441c2aa98e2SPeter Wemm } 442c2aa98e2SPeter Wemm } 443c2aa98e2SPeter Wemm } 444c2aa98e2SPeter Wemm if (trycanon && 445c2aa98e2SPeter Wemm getcanonname(mxhosts[0], sizeof MXHostBuf - 2, FALSE)) 446c2aa98e2SPeter Wemm { 447c2aa98e2SPeter Wemm bp = &MXHostBuf[strlen(MXHostBuf)]; 448c2aa98e2SPeter Wemm if (bp[-1] != '.') 449c2aa98e2SPeter Wemm { 450c2aa98e2SPeter Wemm *bp++ = '.'; 451c2aa98e2SPeter Wemm *bp = '\0'; 452c2aa98e2SPeter Wemm } 453c2aa98e2SPeter Wemm nmx = 1; 454c2aa98e2SPeter Wemm } 455c2aa98e2SPeter Wemm } 456c2aa98e2SPeter Wemm 457c2aa98e2SPeter Wemm /* if we have a default lowest preference, include that */ 458c2aa98e2SPeter Wemm if (fallbackMX != NULL && !seenlocal) 45906f25ae9SGregory Neil Shapiro { 46006f25ae9SGregory Neil Shapiro if (nmx > 0) 46106f25ae9SGregory Neil Shapiro prefs[nmx] = prefs[nmx - 1] + 1; 46206f25ae9SGregory Neil Shapiro else 46306f25ae9SGregory Neil Shapiro prefs[nmx] = 0; 464c2aa98e2SPeter Wemm mxhosts[nmx++] = fallbackMX; 46506f25ae9SGregory Neil Shapiro } 466c2aa98e2SPeter Wemm 46706f25ae9SGregory Neil Shapiro return nmx; 468c2aa98e2SPeter Wemm } 469c2aa98e2SPeter Wemm /* 470c2aa98e2SPeter Wemm ** MXRAND -- create a randomizer for equal MX preferences 471c2aa98e2SPeter Wemm ** 472c2aa98e2SPeter Wemm ** If two MX hosts have equal preferences we want to randomize 473c2aa98e2SPeter Wemm ** the selection. But in order for signatures to be the same, 474c2aa98e2SPeter Wemm ** we need to randomize the same way each time. This function 475c2aa98e2SPeter Wemm ** computes a pseudo-random hash function from the host name. 476c2aa98e2SPeter Wemm ** 477c2aa98e2SPeter Wemm ** Parameters: 478c2aa98e2SPeter Wemm ** host -- the name of the host. 479c2aa98e2SPeter Wemm ** 480c2aa98e2SPeter Wemm ** Returns: 481c2aa98e2SPeter Wemm ** A random but repeatable value based on the host name. 482c2aa98e2SPeter Wemm ** 483c2aa98e2SPeter Wemm ** Side Effects: 484c2aa98e2SPeter Wemm ** none. 485c2aa98e2SPeter Wemm */ 486c2aa98e2SPeter Wemm 48706f25ae9SGregory Neil Shapiro static int 488c2aa98e2SPeter Wemm mxrand(host) 489c2aa98e2SPeter Wemm register char *host; 490c2aa98e2SPeter Wemm { 491c2aa98e2SPeter Wemm int hfunc; 492c2aa98e2SPeter Wemm static unsigned int seed; 493c2aa98e2SPeter Wemm 494c2aa98e2SPeter Wemm if (seed == 0) 495c2aa98e2SPeter Wemm { 496c2aa98e2SPeter Wemm seed = (int) curtime() & 0xffff; 497c2aa98e2SPeter Wemm if (seed == 0) 498c2aa98e2SPeter Wemm seed++; 499c2aa98e2SPeter Wemm } 500c2aa98e2SPeter Wemm 501c2aa98e2SPeter Wemm if (tTd(17, 9)) 50206f25ae9SGregory Neil Shapiro dprintf("mxrand(%s)", host); 503c2aa98e2SPeter Wemm 504c2aa98e2SPeter Wemm hfunc = seed; 505c2aa98e2SPeter Wemm while (*host != '\0') 506c2aa98e2SPeter Wemm { 507c2aa98e2SPeter Wemm int c = *host++; 508c2aa98e2SPeter Wemm 509c2aa98e2SPeter Wemm if (isascii(c) && isupper(c)) 510c2aa98e2SPeter Wemm c = tolower(c); 511c2aa98e2SPeter Wemm hfunc = ((hfunc << 1) ^ c) % 2003; 512c2aa98e2SPeter Wemm } 513c2aa98e2SPeter Wemm 514c2aa98e2SPeter Wemm hfunc &= 0xff; 515c2aa98e2SPeter Wemm hfunc++; 516c2aa98e2SPeter Wemm 517c2aa98e2SPeter Wemm if (tTd(17, 9)) 51806f25ae9SGregory Neil Shapiro dprintf(" = %d\n", hfunc); 519c2aa98e2SPeter Wemm return hfunc; 520c2aa98e2SPeter Wemm } 521c2aa98e2SPeter Wemm /* 522c2aa98e2SPeter Wemm ** BESTMX -- find the best MX for a name 523c2aa98e2SPeter Wemm ** 524c2aa98e2SPeter Wemm ** This is really a hack, but I don't see any obvious way 525c2aa98e2SPeter Wemm ** to generalize it at the moment. 526c2aa98e2SPeter Wemm */ 527c2aa98e2SPeter Wemm 528c2aa98e2SPeter Wemm /* ARGSUSED3 */ 529c2aa98e2SPeter Wemm char * 530c2aa98e2SPeter Wemm bestmx_map_lookup(map, name, av, statp) 531c2aa98e2SPeter Wemm MAP *map; 532c2aa98e2SPeter Wemm char *name; 533c2aa98e2SPeter Wemm char **av; 534c2aa98e2SPeter Wemm int *statp; 535c2aa98e2SPeter Wemm { 536c2aa98e2SPeter Wemm int nmx; 537c2aa98e2SPeter Wemm int saveopts = _res.options; 538c2aa98e2SPeter Wemm int i, len = 0; 539c2aa98e2SPeter Wemm char *p; 540c2aa98e2SPeter Wemm char *mxhosts[MAXMXHOSTS + 1]; 541065a643dSPeter Wemm char buf[PSBUFSIZE / 2]; 542c2aa98e2SPeter Wemm 543c2aa98e2SPeter Wemm _res.options &= ~(RES_DNSRCH|RES_DEFNAMES); 54406f25ae9SGregory Neil Shapiro nmx = getmxrr(name, mxhosts, NULL, FALSE, statp); 545c2aa98e2SPeter Wemm _res.options = saveopts; 546c2aa98e2SPeter Wemm if (nmx <= 0) 547c2aa98e2SPeter Wemm return NULL; 548c2aa98e2SPeter Wemm if (bitset(MF_MATCHONLY, map->map_mflags)) 549c2aa98e2SPeter Wemm return map_rewrite(map, name, strlen(name), NULL); 550c2aa98e2SPeter Wemm if ((map->map_coldelim == '\0') || (nmx == 1)) 551c2aa98e2SPeter Wemm return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av); 552c2aa98e2SPeter Wemm 553c2aa98e2SPeter Wemm /* 554c2aa98e2SPeter Wemm ** We were given a -z flag (return all MXs) and there are multiple 555c2aa98e2SPeter Wemm ** ones. We need to build them all into a list. 556c2aa98e2SPeter Wemm */ 557c2aa98e2SPeter Wemm p = buf; 558c2aa98e2SPeter Wemm for (i = 0; i < nmx; i++) 559c2aa98e2SPeter Wemm { 560c2aa98e2SPeter Wemm int slen; 561c2aa98e2SPeter Wemm 562c2aa98e2SPeter Wemm if (strchr(mxhosts[i], map->map_coldelim) != NULL) 563c2aa98e2SPeter Wemm { 564c2aa98e2SPeter Wemm syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 565c2aa98e2SPeter Wemm mxhosts[i], map->map_coldelim); 566c2aa98e2SPeter Wemm return NULL; 567c2aa98e2SPeter Wemm } 568c2aa98e2SPeter Wemm slen = strlen(mxhosts[i]); 569c2aa98e2SPeter Wemm if (len + slen + 2 > sizeof buf) 570c2aa98e2SPeter Wemm break; 571c2aa98e2SPeter Wemm if (i > 0) 572c2aa98e2SPeter Wemm { 573c2aa98e2SPeter Wemm *p++ = map->map_coldelim; 574c2aa98e2SPeter Wemm len++; 575c2aa98e2SPeter Wemm } 57606f25ae9SGregory Neil Shapiro (void) strlcpy(p, mxhosts[i], sizeof buf - len); 577c2aa98e2SPeter Wemm p += slen; 578c2aa98e2SPeter Wemm len += slen; 579c2aa98e2SPeter Wemm } 580c2aa98e2SPeter Wemm return map_rewrite(map, buf, len, av); 581c2aa98e2SPeter Wemm } 582c2aa98e2SPeter Wemm /* 583c2aa98e2SPeter Wemm ** DNS_GETCANONNAME -- get the canonical name for named host using DNS 584c2aa98e2SPeter Wemm ** 585c2aa98e2SPeter Wemm ** This algorithm tries to be smart about wildcard MX records. 586c2aa98e2SPeter Wemm ** This is hard to do because DNS doesn't tell is if we matched 587c2aa98e2SPeter Wemm ** against a wildcard or a specific MX. 588c2aa98e2SPeter Wemm ** 589c2aa98e2SPeter Wemm ** We always prefer A & CNAME records, since these are presumed 590c2aa98e2SPeter Wemm ** to be specific. 591c2aa98e2SPeter Wemm ** 592c2aa98e2SPeter Wemm ** If we match an MX in one pass and lose it in the next, we use 593c2aa98e2SPeter Wemm ** the old one. For example, consider an MX matching *.FOO.BAR.COM. 594c2aa98e2SPeter Wemm ** A hostname bletch.foo.bar.com will match against this MX, but 595c2aa98e2SPeter Wemm ** will stop matching when we try bletch.bar.com -- so we know 596c2aa98e2SPeter Wemm ** that bletch.foo.bar.com must have been right. This fails if 597c2aa98e2SPeter Wemm ** there was also an MX record matching *.BAR.COM, but there are 598c2aa98e2SPeter Wemm ** some things that just can't be fixed. 599c2aa98e2SPeter Wemm ** 600c2aa98e2SPeter Wemm ** Parameters: 601c2aa98e2SPeter Wemm ** host -- a buffer containing the name of the host. 602c2aa98e2SPeter Wemm ** This is a value-result parameter. 603c2aa98e2SPeter Wemm ** hbsize -- the size of the host buffer. 604c2aa98e2SPeter Wemm ** trymx -- if set, try MX records as well as A and CNAME. 605c2aa98e2SPeter Wemm ** statp -- pointer to place to store status. 606c2aa98e2SPeter Wemm ** 607c2aa98e2SPeter Wemm ** Returns: 608c2aa98e2SPeter Wemm ** TRUE -- if the host matched. 609c2aa98e2SPeter Wemm ** FALSE -- otherwise. 610c2aa98e2SPeter Wemm */ 611c2aa98e2SPeter Wemm 612c2aa98e2SPeter Wemm bool 613c2aa98e2SPeter Wemm dns_getcanonname(host, hbsize, trymx, statp) 614c2aa98e2SPeter Wemm char *host; 615c2aa98e2SPeter Wemm int hbsize; 616c2aa98e2SPeter Wemm bool trymx; 617c2aa98e2SPeter Wemm int *statp; 618c2aa98e2SPeter Wemm { 619c2aa98e2SPeter Wemm register u_char *eom, *ap; 620c2aa98e2SPeter Wemm register char *cp; 621c2aa98e2SPeter Wemm register int n; 622c2aa98e2SPeter Wemm HEADER *hp; 623c2aa98e2SPeter Wemm querybuf answer; 624c2aa98e2SPeter Wemm int ancount, qdcount; 625c2aa98e2SPeter Wemm int ret; 626c2aa98e2SPeter Wemm char **domain; 627c2aa98e2SPeter Wemm int type; 628c2aa98e2SPeter Wemm char **dp; 629c2aa98e2SPeter Wemm char *mxmatch; 630c2aa98e2SPeter Wemm bool amatch; 631c2aa98e2SPeter Wemm bool gotmx = FALSE; 632c2aa98e2SPeter Wemm int qtype; 633c2aa98e2SPeter Wemm int loopcnt; 634c2aa98e2SPeter Wemm char *xp; 635c2aa98e2SPeter Wemm char nbuf[MAX(MAXPACKET, MAXDNAME*2+2)]; 636c2aa98e2SPeter Wemm char *searchlist[MAXDNSRCH+2]; 637c2aa98e2SPeter Wemm 638c2aa98e2SPeter Wemm if (tTd(8, 2)) 63906f25ae9SGregory Neil Shapiro dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx); 640c2aa98e2SPeter Wemm 641c2aa98e2SPeter Wemm if ((_res.options & RES_INIT) == 0 && res_init() == -1) 642c2aa98e2SPeter Wemm { 643c2aa98e2SPeter Wemm *statp = EX_UNAVAILABLE; 644c2aa98e2SPeter Wemm return FALSE; 645c2aa98e2SPeter Wemm } 646c2aa98e2SPeter Wemm 647193538b7SGregory Neil Shapiro *statp = EX_OK; 648193538b7SGregory Neil Shapiro 649c2aa98e2SPeter Wemm /* 650c2aa98e2SPeter Wemm ** Initialize domain search list. If there is at least one 651c2aa98e2SPeter Wemm ** dot in the name, search the unmodified name first so we 652c2aa98e2SPeter Wemm ** find "vse.CS" in Czechoslovakia instead of in the local 65306f25ae9SGregory Neil Shapiro ** domain (e.g., vse.CS.Berkeley.EDU). Note that there is no 65406f25ae9SGregory Neil Shapiro ** longer a country named Czechoslovakia but this type of problem 65506f25ae9SGregory Neil Shapiro ** is still present. 656c2aa98e2SPeter Wemm ** 657c2aa98e2SPeter Wemm ** Older versions of the resolver could create this 658c2aa98e2SPeter Wemm ** list by tearing apart the host name. 659c2aa98e2SPeter Wemm */ 660c2aa98e2SPeter Wemm 661c2aa98e2SPeter Wemm loopcnt = 0; 662c2aa98e2SPeter Wemm cnameloop: 663c2aa98e2SPeter Wemm /* Check for dots in the name */ 664c2aa98e2SPeter Wemm for (cp = host, n = 0; *cp != '\0'; cp++) 665c2aa98e2SPeter Wemm if (*cp == '.') 666c2aa98e2SPeter Wemm n++; 667c2aa98e2SPeter Wemm 668c2aa98e2SPeter Wemm /* 669c2aa98e2SPeter Wemm ** If this is a simple name, determine whether it matches an 670c2aa98e2SPeter Wemm ** alias in the file defined by the environment variable HOSTALIASES. 671c2aa98e2SPeter Wemm */ 672c2aa98e2SPeter Wemm if (n == 0 && (xp = gethostalias(host)) != NULL) 673c2aa98e2SPeter Wemm { 674c2aa98e2SPeter Wemm if (loopcnt++ > MAXCNAMEDEPTH) 675c2aa98e2SPeter Wemm { 676c2aa98e2SPeter Wemm syserr("loop in ${HOSTALIASES} file"); 677c2aa98e2SPeter Wemm } 678c2aa98e2SPeter Wemm else 679c2aa98e2SPeter Wemm { 68006f25ae9SGregory Neil Shapiro (void) strlcpy(host, xp, hbsize); 681c2aa98e2SPeter Wemm goto cnameloop; 682c2aa98e2SPeter Wemm } 683c2aa98e2SPeter Wemm } 684c2aa98e2SPeter Wemm 685c2aa98e2SPeter Wemm /* 686c2aa98e2SPeter Wemm ** Build the search list. 687c2aa98e2SPeter Wemm ** If there is at least one dot in name, start with a null 688c2aa98e2SPeter Wemm ** domain to search the unmodified name first. 689c2aa98e2SPeter Wemm ** If name does not end with a dot and search up local domain 690c2aa98e2SPeter Wemm ** tree desired, append each local domain component to the 691c2aa98e2SPeter Wemm ** search list; if name contains no dots and default domain 692c2aa98e2SPeter Wemm ** name is desired, append default domain name to search list; 693c2aa98e2SPeter Wemm ** else if name ends in a dot, remove that dot. 694c2aa98e2SPeter Wemm */ 695c2aa98e2SPeter Wemm 696c2aa98e2SPeter Wemm dp = searchlist; 697c2aa98e2SPeter Wemm if (n > 0) 698c2aa98e2SPeter Wemm *dp++ = ""; 699c2aa98e2SPeter Wemm if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options)) 700c2aa98e2SPeter Wemm { 70106f25ae9SGregory Neil Shapiro /* make sure there are less than MAXDNSRCH domains */ 70206f25ae9SGregory Neil Shapiro for (domain = RES_DNSRCH_VARIABLE, ret = 0; 70306f25ae9SGregory Neil Shapiro *domain != NULL && ret < MAXDNSRCH; 70406f25ae9SGregory Neil Shapiro ret++) 705c2aa98e2SPeter Wemm *dp++ = *domain++; 706c2aa98e2SPeter Wemm } 707c2aa98e2SPeter Wemm else if (n == 0 && bitset(RES_DEFNAMES, _res.options)) 708c2aa98e2SPeter Wemm { 709c2aa98e2SPeter Wemm *dp++ = _res.defdname; 710c2aa98e2SPeter Wemm } 711c2aa98e2SPeter Wemm else if (*cp == '.') 712c2aa98e2SPeter Wemm { 713c2aa98e2SPeter Wemm *cp = '\0'; 714c2aa98e2SPeter Wemm } 715c2aa98e2SPeter Wemm *dp = NULL; 716c2aa98e2SPeter Wemm 717c2aa98e2SPeter Wemm /* 718c2aa98e2SPeter Wemm ** Now loop through the search list, appending each domain in turn 719c2aa98e2SPeter Wemm ** name and searching for a match. 720c2aa98e2SPeter Wemm */ 721c2aa98e2SPeter Wemm 722c2aa98e2SPeter Wemm mxmatch = NULL; 723c2aa98e2SPeter Wemm qtype = T_ANY; 724c2aa98e2SPeter Wemm 725c2aa98e2SPeter Wemm for (dp = searchlist; *dp != NULL; ) 726c2aa98e2SPeter Wemm { 727c2aa98e2SPeter Wemm if (qtype == T_ANY) 728c2aa98e2SPeter Wemm gotmx = FALSE; 729c2aa98e2SPeter Wemm if (tTd(8, 5)) 73006f25ae9SGregory Neil Shapiro dprintf("dns_getcanonname: trying %s.%s (%s)\n", 731c2aa98e2SPeter Wemm host, *dp, 73206f25ae9SGregory Neil Shapiro qtype == T_ANY ? "ANY" : 73306f25ae9SGregory Neil Shapiro # if NETINET6 73406f25ae9SGregory Neil Shapiro qtype == T_AAAA ? "AAAA" : 73506f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 73606f25ae9SGregory Neil Shapiro qtype == T_A ? "A" : 73706f25ae9SGregory Neil Shapiro qtype == T_MX ? "MX" : 73806f25ae9SGregory Neil Shapiro "???"); 739193538b7SGregory Neil Shapiro errno = 0; 740c2aa98e2SPeter Wemm ret = res_querydomain(host, *dp, C_IN, qtype, 741c2aa98e2SPeter Wemm answer.qb2, sizeof(answer.qb2)); 742c2aa98e2SPeter Wemm if (ret <= 0) 743c2aa98e2SPeter Wemm { 744c2aa98e2SPeter Wemm if (tTd(8, 7)) 74506f25ae9SGregory Neil Shapiro dprintf("\tNO: errno=%d, h_errno=%d\n", 746c2aa98e2SPeter Wemm errno, h_errno); 747c2aa98e2SPeter Wemm 748c2aa98e2SPeter Wemm if (errno == ECONNREFUSED || h_errno == TRY_AGAIN) 749c2aa98e2SPeter Wemm { 750193538b7SGregory Neil Shapiro /* 751193538b7SGregory Neil Shapiro ** the name server seems to be down or 752193538b7SGregory Neil Shapiro ** broken. 753193538b7SGregory Neil Shapiro */ 754193538b7SGregory Neil Shapiro 755602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(TRY_AGAIN); 756c2aa98e2SPeter Wemm *statp = EX_TEMPFAIL; 75706f25ae9SGregory Neil Shapiro 75806f25ae9SGregory Neil Shapiro /* 75906f25ae9SGregory Neil Shapiro ** If the ANY query is larger than the 76006f25ae9SGregory Neil Shapiro ** UDP packet size, the resolver will 76106f25ae9SGregory Neil Shapiro ** fall back to TCP. However, some 76206f25ae9SGregory Neil Shapiro ** misconfigured firewalls block 53/TCP 76306f25ae9SGregory Neil Shapiro ** so the ANY lookup fails whereas an MX 76406f25ae9SGregory Neil Shapiro ** or A record might work. Therefore, 76506f25ae9SGregory Neil Shapiro ** don't fail on ANY queries. 76606f25ae9SGregory Neil Shapiro ** 76706f25ae9SGregory Neil Shapiro ** The ANY query is really meant to prime 76806f25ae9SGregory Neil Shapiro ** the cache so this isn't dangerous. 76906f25ae9SGregory Neil Shapiro */ 77006f25ae9SGregory Neil Shapiro 771193538b7SGregory Neil Shapiro #if _FFR_WORKAROUND_BROKEN_NAMESERVERS 772602a2b1bSGregory Neil Shapiro if (WorkAroundBrokenAAAA) 773602a2b1bSGregory Neil Shapiro { 774193538b7SGregory Neil Shapiro /* 775193538b7SGregory Neil Shapiro ** Only return if not TRY_AGAIN as an 776193538b7SGregory Neil Shapiro ** attempt with a different qtype may 777193538b7SGregory Neil Shapiro ** succeed (res_querydomain() calls 778193538b7SGregory Neil Shapiro ** res_query() calls res_send() which 779193538b7SGregory Neil Shapiro ** sets errno to ETIMEDOUT if the 780193538b7SGregory Neil Shapiro ** nameservers could be contacted but 781193538b7SGregory Neil Shapiro ** didn't give an answer). 782193538b7SGregory Neil Shapiro */ 783193538b7SGregory Neil Shapiro 784602a2b1bSGregory Neil Shapiro if (qtype != T_ANY && 785602a2b1bSGregory Neil Shapiro errno != ETIMEDOUT) 786193538b7SGregory Neil Shapiro return FALSE; 787602a2b1bSGregory Neil Shapiro } 788193538b7SGregory Neil Shapiro #else /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */ 78906f25ae9SGregory Neil Shapiro if (qtype != T_ANY) 790c2aa98e2SPeter Wemm return FALSE; 791193538b7SGregory Neil Shapiro #endif /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */ 792c2aa98e2SPeter Wemm } 793c2aa98e2SPeter Wemm 794c2aa98e2SPeter Wemm if (h_errno != HOST_NOT_FOUND) 795c2aa98e2SPeter Wemm { 796c2aa98e2SPeter Wemm /* might have another type of interest */ 797c2aa98e2SPeter Wemm if (qtype == T_ANY) 798c2aa98e2SPeter Wemm { 79906f25ae9SGregory Neil Shapiro # if NETINET6 80006f25ae9SGregory Neil Shapiro qtype = T_AAAA; 80106f25ae9SGregory Neil Shapiro # else /* NETINET6 */ 80206f25ae9SGregory Neil Shapiro qtype = T_A; 80306f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 80406f25ae9SGregory Neil Shapiro continue; 80506f25ae9SGregory Neil Shapiro } 80606f25ae9SGregory Neil Shapiro # if NETINET6 80706f25ae9SGregory Neil Shapiro else if (qtype == T_AAAA) 80806f25ae9SGregory Neil Shapiro { 809c2aa98e2SPeter Wemm qtype = T_A; 810c2aa98e2SPeter Wemm continue; 811c2aa98e2SPeter Wemm } 81206f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 81306f25ae9SGregory Neil Shapiro else if (qtype == T_A && !gotmx && 81406f25ae9SGregory Neil Shapiro (trymx || **dp == '\0')) 815c2aa98e2SPeter Wemm { 816c2aa98e2SPeter Wemm qtype = T_MX; 817c2aa98e2SPeter Wemm continue; 818c2aa98e2SPeter Wemm } 819c2aa98e2SPeter Wemm } 820c2aa98e2SPeter Wemm 821c2aa98e2SPeter Wemm /* definite no -- try the next domain */ 822c2aa98e2SPeter Wemm dp++; 823c2aa98e2SPeter Wemm qtype = T_ANY; 824c2aa98e2SPeter Wemm continue; 825c2aa98e2SPeter Wemm } 826c2aa98e2SPeter Wemm else if (tTd(8, 7)) 82706f25ae9SGregory Neil Shapiro dprintf("\tYES\n"); 828c2aa98e2SPeter Wemm 829c2aa98e2SPeter Wemm /* avoid problems after truncation in tcp packets */ 830c2aa98e2SPeter Wemm if (ret > sizeof(answer)) 831c2aa98e2SPeter Wemm ret = sizeof(answer); 832c2aa98e2SPeter Wemm 833c2aa98e2SPeter Wemm /* 834c2aa98e2SPeter Wemm ** Appear to have a match. Confirm it by searching for A or 835c2aa98e2SPeter Wemm ** CNAME records. If we don't have a local domain 836c2aa98e2SPeter Wemm ** wild card MX record, we will accept MX as well. 837c2aa98e2SPeter Wemm */ 838c2aa98e2SPeter Wemm 839c2aa98e2SPeter Wemm hp = (HEADER *) &answer; 840c2aa98e2SPeter Wemm ap = (u_char *) &answer + HFIXEDSZ; 841c2aa98e2SPeter Wemm eom = (u_char *) &answer + ret; 842c2aa98e2SPeter Wemm 843c2aa98e2SPeter Wemm /* skip question part of response -- we know what we asked */ 84406f25ae9SGregory Neil Shapiro for (qdcount = ntohs((u_short)hp->qdcount); 84506f25ae9SGregory Neil Shapiro qdcount--; 84606f25ae9SGregory Neil Shapiro ap += ret + QFIXEDSZ) 847c2aa98e2SPeter Wemm { 848c2aa98e2SPeter Wemm if ((ret = dn_skipname(ap, eom)) < 0) 849c2aa98e2SPeter Wemm { 850c2aa98e2SPeter Wemm if (tTd(8, 20)) 85106f25ae9SGregory Neil Shapiro dprintf("qdcount failure (%d)\n", 85206f25ae9SGregory Neil Shapiro ntohs((u_short)hp->qdcount)); 853c2aa98e2SPeter Wemm *statp = EX_SOFTWARE; 854c2aa98e2SPeter Wemm return FALSE; /* ???XXX??? */ 855c2aa98e2SPeter Wemm } 856c2aa98e2SPeter Wemm } 857c2aa98e2SPeter Wemm 858c2aa98e2SPeter Wemm amatch = FALSE; 85906f25ae9SGregory Neil Shapiro for (ancount = ntohs((u_short)hp->ancount); 86006f25ae9SGregory Neil Shapiro --ancount >= 0 && ap < eom; 861c2aa98e2SPeter Wemm ap += n) 862c2aa98e2SPeter Wemm { 863c2aa98e2SPeter Wemm n = dn_expand((u_char *) &answer, eom, ap, 864c2aa98e2SPeter Wemm (RES_UNC_T) nbuf, sizeof nbuf); 865c2aa98e2SPeter Wemm if (n < 0) 866c2aa98e2SPeter Wemm break; 867c2aa98e2SPeter Wemm ap += n; 868c2aa98e2SPeter Wemm GETSHORT(type, ap); 869c2aa98e2SPeter Wemm ap += INT16SZ + INT32SZ; 870c2aa98e2SPeter Wemm GETSHORT(n, ap); 871c2aa98e2SPeter Wemm switch (type) 872c2aa98e2SPeter Wemm { 873c2aa98e2SPeter Wemm case T_MX: 874c2aa98e2SPeter Wemm gotmx = TRUE; 875c2aa98e2SPeter Wemm if (**dp != '\0' && HasWildcardMX) 876c2aa98e2SPeter Wemm { 877c2aa98e2SPeter Wemm /* 878c2aa98e2SPeter Wemm ** If we are using MX matches and have 879c2aa98e2SPeter Wemm ** not yet gotten one, save this one 880c2aa98e2SPeter Wemm ** but keep searching for an A or 881c2aa98e2SPeter Wemm ** CNAME match. 882c2aa98e2SPeter Wemm */ 883c2aa98e2SPeter Wemm 884c2aa98e2SPeter Wemm if (trymx && mxmatch == NULL) 885c2aa98e2SPeter Wemm mxmatch = *dp; 886c2aa98e2SPeter Wemm continue; 887c2aa98e2SPeter Wemm } 888c2aa98e2SPeter Wemm 889c2aa98e2SPeter Wemm /* 890c2aa98e2SPeter Wemm ** If we did not append a domain name, this 891c2aa98e2SPeter Wemm ** must have been a canonical name to start 892c2aa98e2SPeter Wemm ** with. Even if we did append a domain name, 893c2aa98e2SPeter Wemm ** in the absence of a wildcard MX this must 894c2aa98e2SPeter Wemm ** still be a real MX match. 895c2aa98e2SPeter Wemm ** Such MX matches are as good as an A match, 896c2aa98e2SPeter Wemm ** fall through. 897c2aa98e2SPeter Wemm */ 89806f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 89906f25ae9SGregory Neil Shapiro 90006f25ae9SGregory Neil Shapiro # if NETINET6 90106f25ae9SGregory Neil Shapiro case T_AAAA: 90206f25ae9SGregory Neil Shapiro /* Flag that a good match was found */ 90306f25ae9SGregory Neil Shapiro amatch = TRUE; 90406f25ae9SGregory Neil Shapiro 90506f25ae9SGregory Neil Shapiro /* continue in case a CNAME also exists */ 90606f25ae9SGregory Neil Shapiro continue; 90706f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 908c2aa98e2SPeter Wemm 909c2aa98e2SPeter Wemm case T_A: 910c2aa98e2SPeter Wemm /* Flag that a good match was found */ 911c2aa98e2SPeter Wemm amatch = TRUE; 912c2aa98e2SPeter Wemm 913c2aa98e2SPeter Wemm /* continue in case a CNAME also exists */ 914c2aa98e2SPeter Wemm continue; 915c2aa98e2SPeter Wemm 916c2aa98e2SPeter Wemm case T_CNAME: 917c2aa98e2SPeter Wemm if (DontExpandCnames) 918c2aa98e2SPeter Wemm { 919c2aa98e2SPeter Wemm /* got CNAME -- guaranteed canonical */ 920c2aa98e2SPeter Wemm amatch = TRUE; 921c2aa98e2SPeter Wemm break; 922c2aa98e2SPeter Wemm } 923c2aa98e2SPeter Wemm 924c2aa98e2SPeter Wemm if (loopcnt++ > MAXCNAMEDEPTH) 925c2aa98e2SPeter Wemm { 926c2aa98e2SPeter Wemm /*XXX should notify postmaster XXX*/ 927c2aa98e2SPeter Wemm message("DNS failure: CNAME loop for %s", 928c2aa98e2SPeter Wemm host); 929c2aa98e2SPeter Wemm if (CurEnv->e_message == NULL) 930c2aa98e2SPeter Wemm { 931c2aa98e2SPeter Wemm char ebuf[MAXLINE]; 932c2aa98e2SPeter Wemm 933c2aa98e2SPeter Wemm snprintf(ebuf, sizeof ebuf, 934c2aa98e2SPeter Wemm "Deferred: DNS failure: CNAME loop for %.100s", 935c2aa98e2SPeter Wemm host); 936c2aa98e2SPeter Wemm CurEnv->e_message = newstr(ebuf); 937c2aa98e2SPeter Wemm } 938602a2b1bSGregory Neil Shapiro SM_SET_H_ERRNO(NO_RECOVERY); 939c2aa98e2SPeter Wemm *statp = EX_CONFIG; 940c2aa98e2SPeter Wemm return FALSE; 941c2aa98e2SPeter Wemm } 942c2aa98e2SPeter Wemm 943c2aa98e2SPeter Wemm /* value points at name */ 944c2aa98e2SPeter Wemm if ((ret = dn_expand((u_char *)&answer, 945c2aa98e2SPeter Wemm eom, ap, (RES_UNC_T) nbuf, sizeof(nbuf))) < 0) 946c2aa98e2SPeter Wemm break; 94706f25ae9SGregory Neil Shapiro (void)strlcpy(host, nbuf, hbsize); 948c2aa98e2SPeter Wemm 949c2aa98e2SPeter Wemm /* 950c2aa98e2SPeter Wemm ** RFC 1034 section 3.6 specifies that CNAME 951c2aa98e2SPeter Wemm ** should point at the canonical name -- but 952c2aa98e2SPeter Wemm ** urges software to try again anyway. 953c2aa98e2SPeter Wemm */ 954c2aa98e2SPeter Wemm 955c2aa98e2SPeter Wemm goto cnameloop; 956c2aa98e2SPeter Wemm 957c2aa98e2SPeter Wemm default: 958c2aa98e2SPeter Wemm /* not a record of interest */ 959c2aa98e2SPeter Wemm continue; 960c2aa98e2SPeter Wemm } 961c2aa98e2SPeter Wemm } 962c2aa98e2SPeter Wemm 963c2aa98e2SPeter Wemm if (amatch) 964c2aa98e2SPeter Wemm { 965c2aa98e2SPeter Wemm /* 966c2aa98e2SPeter Wemm ** Got a good match -- either an A, CNAME, or an 967c2aa98e2SPeter Wemm ** exact MX record. Save it and get out of here. 968c2aa98e2SPeter Wemm */ 969c2aa98e2SPeter Wemm 970c2aa98e2SPeter Wemm mxmatch = *dp; 971c2aa98e2SPeter Wemm break; 972c2aa98e2SPeter Wemm } 973c2aa98e2SPeter Wemm 974c2aa98e2SPeter Wemm /* 975c2aa98e2SPeter Wemm ** Nothing definitive yet. 976c2aa98e2SPeter Wemm ** If this was a T_ANY query, we don't really know what 977c2aa98e2SPeter Wemm ** was returned -- it might have been a T_NS, 978c2aa98e2SPeter Wemm ** for example. Try T_A to be more specific 979c2aa98e2SPeter Wemm ** during the next pass. 980c2aa98e2SPeter Wemm ** If this was a T_A query and we haven't yet found a MX 981c2aa98e2SPeter Wemm ** match, try T_MX if allowed to do so. 982c2aa98e2SPeter Wemm ** Otherwise, try the next domain. 983c2aa98e2SPeter Wemm */ 984c2aa98e2SPeter Wemm 985c2aa98e2SPeter Wemm if (qtype == T_ANY) 98606f25ae9SGregory Neil Shapiro { 98706f25ae9SGregory Neil Shapiro # if NETINET6 98806f25ae9SGregory Neil Shapiro qtype = T_AAAA; 98906f25ae9SGregory Neil Shapiro # else /* NETINET6 */ 990c2aa98e2SPeter Wemm qtype = T_A; 99106f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 99206f25ae9SGregory Neil Shapiro } 99306f25ae9SGregory Neil Shapiro # if NETINET6 99406f25ae9SGregory Neil Shapiro else if (qtype == T_AAAA) 99506f25ae9SGregory Neil Shapiro qtype = T_A; 99606f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 997065a643dSPeter Wemm else if (qtype == T_A && !gotmx && (trymx || **dp == '\0')) 998c2aa98e2SPeter Wemm qtype = T_MX; 999c2aa98e2SPeter Wemm else 1000c2aa98e2SPeter Wemm { 1001c2aa98e2SPeter Wemm qtype = T_ANY; 1002c2aa98e2SPeter Wemm dp++; 1003c2aa98e2SPeter Wemm } 1004c2aa98e2SPeter Wemm } 1005c2aa98e2SPeter Wemm 1006c2aa98e2SPeter Wemm /* if nothing was found, we are done */ 1007c2aa98e2SPeter Wemm if (mxmatch == NULL) 1008c2aa98e2SPeter Wemm { 1009193538b7SGregory Neil Shapiro if (*statp == EX_OK) 1010c2aa98e2SPeter Wemm *statp = EX_NOHOST; 1011c2aa98e2SPeter Wemm return FALSE; 1012c2aa98e2SPeter Wemm } 1013c2aa98e2SPeter Wemm 1014c2aa98e2SPeter Wemm /* 1015c2aa98e2SPeter Wemm ** Create canonical name and return. 1016c2aa98e2SPeter Wemm ** If saved domain name is null, name was already canonical. 1017c2aa98e2SPeter Wemm ** Otherwise append the saved domain name. 1018c2aa98e2SPeter Wemm */ 1019c2aa98e2SPeter Wemm 1020c2aa98e2SPeter Wemm (void) snprintf(nbuf, sizeof nbuf, "%.*s%s%.*s", MAXDNAME, host, 1021c2aa98e2SPeter Wemm *mxmatch == '\0' ? "" : ".", 1022c2aa98e2SPeter Wemm MAXDNAME, mxmatch); 102306f25ae9SGregory Neil Shapiro (void) strlcpy(host, nbuf, hbsize); 1024c2aa98e2SPeter Wemm if (tTd(8, 5)) 102506f25ae9SGregory Neil Shapiro dprintf("dns_getcanonname: %s\n", host); 1026c2aa98e2SPeter Wemm *statp = EX_OK; 1027c2aa98e2SPeter Wemm return TRUE; 1028c2aa98e2SPeter Wemm } 1029c2aa98e2SPeter Wemm 103006f25ae9SGregory Neil Shapiro static char * 1031c2aa98e2SPeter Wemm gethostalias(host) 1032c2aa98e2SPeter Wemm char *host; 1033c2aa98e2SPeter Wemm { 1034c2aa98e2SPeter Wemm char *fname; 1035c2aa98e2SPeter Wemm FILE *fp; 1036c2aa98e2SPeter Wemm register char *p = NULL; 103706f25ae9SGregory Neil Shapiro long sff = SFF_REGONLY; 1038c2aa98e2SPeter Wemm char buf[MAXLINE]; 1039c2aa98e2SPeter Wemm static char hbuf[MAXDNAME]; 1040c2aa98e2SPeter Wemm 1041c2aa98e2SPeter Wemm if (DontLockReadFiles) 1042c2aa98e2SPeter Wemm sff |= SFF_NOLOCK; 1043c2aa98e2SPeter Wemm fname = getenv("HOSTALIASES"); 1044c2aa98e2SPeter Wemm if (fname == NULL || 1045c2aa98e2SPeter Wemm (fp = safefopen(fname, O_RDONLY, 0, sff)) == NULL) 1046c2aa98e2SPeter Wemm return NULL; 1047c2aa98e2SPeter Wemm while (fgets(buf, sizeof buf, fp) != NULL) 1048c2aa98e2SPeter Wemm { 1049c2aa98e2SPeter Wemm for (p = buf; p != '\0' && !(isascii(*p) && isspace(*p)); p++) 1050c2aa98e2SPeter Wemm continue; 1051c2aa98e2SPeter Wemm if (*p == 0) 1052c2aa98e2SPeter Wemm { 1053c2aa98e2SPeter Wemm /* syntax error */ 1054c2aa98e2SPeter Wemm continue; 1055c2aa98e2SPeter Wemm } 1056c2aa98e2SPeter Wemm *p++ = '\0'; 1057c2aa98e2SPeter Wemm if (strcasecmp(buf, host) == 0) 1058c2aa98e2SPeter Wemm break; 1059c2aa98e2SPeter Wemm } 1060c2aa98e2SPeter Wemm 1061c2aa98e2SPeter Wemm if (feof(fp)) 1062c2aa98e2SPeter Wemm { 1063c2aa98e2SPeter Wemm /* no match */ 106406f25ae9SGregory Neil Shapiro (void) fclose(fp); 1065c2aa98e2SPeter Wemm return NULL; 1066c2aa98e2SPeter Wemm } 106706f25ae9SGregory Neil Shapiro (void) fclose(fp); 1068c2aa98e2SPeter Wemm 1069c2aa98e2SPeter Wemm /* got a match; extract the equivalent name */ 1070c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 1071c2aa98e2SPeter Wemm p++; 1072c2aa98e2SPeter Wemm host = p; 1073c2aa98e2SPeter Wemm while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1074c2aa98e2SPeter Wemm p++; 1075c2aa98e2SPeter Wemm *p = '\0'; 107606f25ae9SGregory Neil Shapiro (void) strlcpy(hbuf, host, sizeof hbuf); 1077c2aa98e2SPeter Wemm return hbuf; 1078c2aa98e2SPeter Wemm } 1079c2aa98e2SPeter Wemm #endif /* NAMED_BIND */ 1080