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