17c478bd9Sstevel@tonic-gate /* 23ee0e492Sjbeck * Copyright (c) 1998-2004, 2006 Sendmail, Inc. and its suppliers. 37c478bd9Sstevel@tonic-gate * All rights reserved. 47c478bd9Sstevel@tonic-gate * Copyright (c) 1986, 1995-1997 Eric P. Allman. All rights reserved. 57c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1993 67c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 97c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 107c478bd9Sstevel@tonic-gate * the sendmail distribution. 117c478bd9Sstevel@tonic-gate * 127c478bd9Sstevel@tonic-gate */ 137c478bd9Sstevel@tonic-gate 147c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 157c478bd9Sstevel@tonic-gate 167c478bd9Sstevel@tonic-gate #include <sendmail.h> 17*058561cbSjbeck #include "map.h" 187c478bd9Sstevel@tonic-gate 197c478bd9Sstevel@tonic-gate #if NAMED_BIND 20*058561cbSjbeck SM_RCSID("@(#)$Id: domain.c,v 8.202 2006/12/19 01:15:07 ca Exp $ (with name server)") 217c478bd9Sstevel@tonic-gate #else /* NAMED_BIND */ 22*058561cbSjbeck SM_RCSID("@(#)$Id: domain.c,v 8.202 2006/12/19 01:15:07 ca Exp $ (without name server)") 237c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #if NAMED_BIND 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate # include <arpa/inet.h> 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate ** The standard udp packet size PACKETSZ (512) is not sufficient for some 327c478bd9Sstevel@tonic-gate ** nameserver answers containing very many resource records. The resolver 337c478bd9Sstevel@tonic-gate ** may switch to tcp and retry if it detects udp packet overflow. 347c478bd9Sstevel@tonic-gate ** Also note that the resolver routines res_query and res_search return 357c478bd9Sstevel@tonic-gate ** the size of the *un*truncated answer in case the supplied answer buffer 367c478bd9Sstevel@tonic-gate ** it not big enough to accommodate the entire answer. 377c478bd9Sstevel@tonic-gate */ 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate # ifndef MAXPACKET 407c478bd9Sstevel@tonic-gate # define MAXPACKET 8192 /* max packet size used internally by BIND */ 417c478bd9Sstevel@tonic-gate # endif /* ! MAXPACKET */ 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate typedef union 447c478bd9Sstevel@tonic-gate { 457c478bd9Sstevel@tonic-gate HEADER qb1; 467c478bd9Sstevel@tonic-gate unsigned char qb2[MAXPACKET]; 477c478bd9Sstevel@tonic-gate } querybuf; 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate # ifndef MXHOSTBUFSIZE 507c478bd9Sstevel@tonic-gate # define MXHOSTBUFSIZE (128 * MAXMXHOSTS) 517c478bd9Sstevel@tonic-gate # endif /* ! MXHOSTBUFSIZE */ 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static char MXHostBuf[MXHOSTBUFSIZE]; 547c478bd9Sstevel@tonic-gate #if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2) 557c478bd9Sstevel@tonic-gate ERROR: _MXHOSTBUFSIZE is out of range 567c478bd9Sstevel@tonic-gate #endif /* (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2) */ 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate # ifndef MAXDNSRCH 597c478bd9Sstevel@tonic-gate # define MAXDNSRCH 6 /* number of possible domains to search */ 607c478bd9Sstevel@tonic-gate # endif /* ! MAXDNSRCH */ 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate # ifndef RES_DNSRCH_VARIABLE 637c478bd9Sstevel@tonic-gate # define RES_DNSRCH_VARIABLE _res.dnsrch 647c478bd9Sstevel@tonic-gate # endif /* ! RES_DNSRCH_VARIABLE */ 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate # ifndef NO_DATA 677c478bd9Sstevel@tonic-gate # define NO_DATA NO_ADDRESS 687c478bd9Sstevel@tonic-gate # endif /* ! NO_DATA */ 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate # ifndef HFIXEDSZ 717c478bd9Sstevel@tonic-gate # define HFIXEDSZ 12 /* sizeof(HEADER) */ 727c478bd9Sstevel@tonic-gate # endif /* ! HFIXEDSZ */ 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate # define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */ 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate # if defined(__RES) && (__RES >= 19940415) 777c478bd9Sstevel@tonic-gate # define RES_UNC_T char * 787c478bd9Sstevel@tonic-gate # else /* defined(__RES) && (__RES >= 19940415) */ 797c478bd9Sstevel@tonic-gate # define RES_UNC_T unsigned char * 807c478bd9Sstevel@tonic-gate # endif /* defined(__RES) && (__RES >= 19940415) */ 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate static int mxrand __P((char *)); 837c478bd9Sstevel@tonic-gate static int fallbackmxrr __P((int, unsigned short *, char **)); 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate /* 867c478bd9Sstevel@tonic-gate ** GETFALLBACKMXRR -- get MX resource records for fallback MX host. 877c478bd9Sstevel@tonic-gate ** 887c478bd9Sstevel@tonic-gate ** We have to initialize this once before doing anything else. 897c478bd9Sstevel@tonic-gate ** Moreover, we have to repeat this from time to time to avoid 907c478bd9Sstevel@tonic-gate ** stale data, e.g., in persistent queue runners. 917c478bd9Sstevel@tonic-gate ** This should be done in a parent process so the child 927c478bd9Sstevel@tonic-gate ** processes have the right data. 937c478bd9Sstevel@tonic-gate ** 947c478bd9Sstevel@tonic-gate ** Parameters: 957c478bd9Sstevel@tonic-gate ** host -- the name of the fallback MX host. 967c478bd9Sstevel@tonic-gate ** 977c478bd9Sstevel@tonic-gate ** Returns: 987c478bd9Sstevel@tonic-gate ** number of MX records. 997c478bd9Sstevel@tonic-gate ** 1007c478bd9Sstevel@tonic-gate ** Side Effects: 1017c478bd9Sstevel@tonic-gate ** Populates NumFallbackMXHosts and fbhosts. 1027c478bd9Sstevel@tonic-gate ** Sets renewal time (based on TTL). 1037c478bd9Sstevel@tonic-gate */ 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate int NumFallbackMXHosts = 0; /* Number of fallback MX hosts (after MX expansion) */ 1067c478bd9Sstevel@tonic-gate static char *fbhosts[MAXMXHOSTS + 1]; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate int 1097c478bd9Sstevel@tonic-gate getfallbackmxrr(host) 1107c478bd9Sstevel@tonic-gate char *host; 1117c478bd9Sstevel@tonic-gate { 1127c478bd9Sstevel@tonic-gate int i, rcode; 1137c478bd9Sstevel@tonic-gate int ttl; 1147c478bd9Sstevel@tonic-gate static time_t renew = 0; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate #if 0 1177c478bd9Sstevel@tonic-gate /* This is currently done before this function is called. */ 1187c478bd9Sstevel@tonic-gate if (host == NULL || *host == '\0') 1197c478bd9Sstevel@tonic-gate return 0; 1207c478bd9Sstevel@tonic-gate #endif /* 0 */ 1217c478bd9Sstevel@tonic-gate if (NumFallbackMXHosts > 0 && renew > curtime()) 1227c478bd9Sstevel@tonic-gate return NumFallbackMXHosts; 1237c478bd9Sstevel@tonic-gate if (host[0] == '[') 1247c478bd9Sstevel@tonic-gate { 1257c478bd9Sstevel@tonic-gate fbhosts[0] = host; 1267c478bd9Sstevel@tonic-gate NumFallbackMXHosts = 1; 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate else 1297c478bd9Sstevel@tonic-gate { 1307c478bd9Sstevel@tonic-gate /* free old data */ 1317c478bd9Sstevel@tonic-gate for (i = 0; i < NumFallbackMXHosts; i++) 1327c478bd9Sstevel@tonic-gate sm_free(fbhosts[i]); 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* get new data */ 1357c478bd9Sstevel@tonic-gate NumFallbackMXHosts = getmxrr(host, fbhosts, NULL, false, 1367c478bd9Sstevel@tonic-gate &rcode, false, &ttl); 1377c478bd9Sstevel@tonic-gate renew = curtime() + ttl; 1387c478bd9Sstevel@tonic-gate for (i = 0; i < NumFallbackMXHosts; i++) 1397c478bd9Sstevel@tonic-gate fbhosts[i] = newstr(fbhosts[i]); 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate return NumFallbackMXHosts; 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate /* 1457c478bd9Sstevel@tonic-gate ** FALLBACKMXRR -- add MX resource records for fallback MX host to list. 1467c478bd9Sstevel@tonic-gate ** 1477c478bd9Sstevel@tonic-gate ** Parameters: 1487c478bd9Sstevel@tonic-gate ** nmx -- current number of MX records. 1497c478bd9Sstevel@tonic-gate ** prefs -- array of preferences. 1507c478bd9Sstevel@tonic-gate ** mxhosts -- array of MX hosts (maximum size: MAXMXHOSTS) 1517c478bd9Sstevel@tonic-gate ** 1527c478bd9Sstevel@tonic-gate ** Returns: 1537c478bd9Sstevel@tonic-gate ** new number of MX records. 1547c478bd9Sstevel@tonic-gate ** 1557c478bd9Sstevel@tonic-gate ** Side Effects: 1567c478bd9Sstevel@tonic-gate ** If FallbackMX was set, it appends the MX records for 1577c478bd9Sstevel@tonic-gate ** that host to mxhosts (and modifies prefs accordingly). 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate static int 1617c478bd9Sstevel@tonic-gate fallbackmxrr(nmx, prefs, mxhosts) 1627c478bd9Sstevel@tonic-gate int nmx; 1637c478bd9Sstevel@tonic-gate unsigned short *prefs; 1647c478bd9Sstevel@tonic-gate char **mxhosts; 1657c478bd9Sstevel@tonic-gate { 1667c478bd9Sstevel@tonic-gate int i; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate for (i = 0; i < NumFallbackMXHosts && nmx < MAXMXHOSTS; i++) 1697c478bd9Sstevel@tonic-gate { 1707c478bd9Sstevel@tonic-gate if (nmx > 0) 1717c478bd9Sstevel@tonic-gate prefs[nmx] = prefs[nmx - 1] + 1; 1727c478bd9Sstevel@tonic-gate else 1737c478bd9Sstevel@tonic-gate prefs[nmx] = 0; 1747c478bd9Sstevel@tonic-gate mxhosts[nmx++] = fbhosts[i]; 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate return nmx; 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate ** GETMXRR -- get MX resource records for a domain 1817c478bd9Sstevel@tonic-gate ** 1827c478bd9Sstevel@tonic-gate ** Parameters: 1837c478bd9Sstevel@tonic-gate ** host -- the name of the host to MX. 1847c478bd9Sstevel@tonic-gate ** mxhosts -- a pointer to a return buffer of MX records. 1857c478bd9Sstevel@tonic-gate ** mxprefs -- a pointer to a return buffer of MX preferences. 1867c478bd9Sstevel@tonic-gate ** If NULL, don't try to populate. 1877c478bd9Sstevel@tonic-gate ** droplocalhost -- If true, all MX records less preferred 1887c478bd9Sstevel@tonic-gate ** than the local host (as determined by $=w) will 1897c478bd9Sstevel@tonic-gate ** be discarded. 1907c478bd9Sstevel@tonic-gate ** rcode -- a pointer to an EX_ status code. 1917c478bd9Sstevel@tonic-gate ** tryfallback -- add also fallback MX host? 1927c478bd9Sstevel@tonic-gate ** pttl -- pointer to return TTL (can be NULL). 1937c478bd9Sstevel@tonic-gate ** 1947c478bd9Sstevel@tonic-gate ** Returns: 1957c478bd9Sstevel@tonic-gate ** The number of MX records found. 1967c478bd9Sstevel@tonic-gate ** -1 if there is an internal failure. 1977c478bd9Sstevel@tonic-gate ** If no MX records are found, mxhosts[0] is set to host 1987c478bd9Sstevel@tonic-gate ** and 1 is returned. 1997c478bd9Sstevel@tonic-gate ** 2007c478bd9Sstevel@tonic-gate ** Side Effects: 2017c478bd9Sstevel@tonic-gate ** The entries made for mxhosts point to a static array 2027c478bd9Sstevel@tonic-gate ** MXHostBuf[MXHOSTBUFSIZE], so the data needs to be copied, 2037c478bd9Sstevel@tonic-gate ** if it must be preserved across calls to this function. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate int 2077c478bd9Sstevel@tonic-gate getmxrr(host, mxhosts, mxprefs, droplocalhost, rcode, tryfallback, pttl) 2087c478bd9Sstevel@tonic-gate char *host; 2097c478bd9Sstevel@tonic-gate char **mxhosts; 2107c478bd9Sstevel@tonic-gate unsigned short *mxprefs; 2117c478bd9Sstevel@tonic-gate bool droplocalhost; 2127c478bd9Sstevel@tonic-gate int *rcode; 2137c478bd9Sstevel@tonic-gate bool tryfallback; 2147c478bd9Sstevel@tonic-gate int *pttl; 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate register unsigned char *eom, *cp; 2177c478bd9Sstevel@tonic-gate register int i, j, n; 2187c478bd9Sstevel@tonic-gate int nmx = 0; 2197c478bd9Sstevel@tonic-gate register char *bp; 2207c478bd9Sstevel@tonic-gate HEADER *hp; 2217c478bd9Sstevel@tonic-gate querybuf answer; 2227c478bd9Sstevel@tonic-gate int ancount, qdcount, buflen; 2237c478bd9Sstevel@tonic-gate bool seenlocal = false; 2247c478bd9Sstevel@tonic-gate unsigned short pref, type; 2257c478bd9Sstevel@tonic-gate unsigned short localpref = 256; 2267c478bd9Sstevel@tonic-gate char *fallbackMX = FallbackMX; 2277c478bd9Sstevel@tonic-gate bool trycanon = false; 2287c478bd9Sstevel@tonic-gate unsigned short *prefs; 2297c478bd9Sstevel@tonic-gate int (*resfunc) __P((const char *, int, int, u_char *, int)); 2307c478bd9Sstevel@tonic-gate unsigned short prefer[MAXMXHOSTS]; 2317c478bd9Sstevel@tonic-gate int weight[MAXMXHOSTS]; 2327c478bd9Sstevel@tonic-gate int ttl = 0; 2337c478bd9Sstevel@tonic-gate extern int res_query(), res_search(); 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate if (tTd(8, 2)) 2367c478bd9Sstevel@tonic-gate sm_dprintf("getmxrr(%s, droplocalhost=%d)\n", 2377c478bd9Sstevel@tonic-gate host, droplocalhost); 2387c478bd9Sstevel@tonic-gate *rcode = EX_OK; 2397c478bd9Sstevel@tonic-gate if (pttl != NULL) 2407c478bd9Sstevel@tonic-gate *pttl = SM_DEFAULT_TTL; 2417c478bd9Sstevel@tonic-gate if (*host == '\0') 2427c478bd9Sstevel@tonic-gate return 0; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate if ((fallbackMX != NULL && droplocalhost && 2457c478bd9Sstevel@tonic-gate wordinclass(fallbackMX, 'w')) || !tryfallback) 2467c478bd9Sstevel@tonic-gate { 2477c478bd9Sstevel@tonic-gate /* don't use fallback for this pass */ 2487c478bd9Sstevel@tonic-gate fallbackMX = NULL; 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate if (mxprefs != NULL) 2527c478bd9Sstevel@tonic-gate prefs = mxprefs; 2537c478bd9Sstevel@tonic-gate else 2547c478bd9Sstevel@tonic-gate prefs = prefer; 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate /* efficiency hack -- numeric or non-MX lookups */ 2577c478bd9Sstevel@tonic-gate if (host[0] == '[') 2587c478bd9Sstevel@tonic-gate goto punt; 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate /* 2617c478bd9Sstevel@tonic-gate ** If we don't have MX records in our host switch, don't 2627c478bd9Sstevel@tonic-gate ** try for MX records. Note that this really isn't "right", 2637c478bd9Sstevel@tonic-gate ** since we might be set up to try NIS first and then DNS; 2647c478bd9Sstevel@tonic-gate ** if the host is found in NIS we really shouldn't be doing 2657c478bd9Sstevel@tonic-gate ** MX lookups. However, that should be a degenerate case. 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate if (!UseNameServer) 2697c478bd9Sstevel@tonic-gate goto punt; 2707c478bd9Sstevel@tonic-gate if (HasWildcardMX && ConfigLevel >= 6) 2717c478bd9Sstevel@tonic-gate resfunc = res_query; 2727c478bd9Sstevel@tonic-gate else 2737c478bd9Sstevel@tonic-gate resfunc = res_search; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate errno = 0; 2767c478bd9Sstevel@tonic-gate n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer, 2777c478bd9Sstevel@tonic-gate sizeof(answer)); 2787c478bd9Sstevel@tonic-gate if (n < 0) 2797c478bd9Sstevel@tonic-gate { 2807c478bd9Sstevel@tonic-gate if (tTd(8, 1)) 2817c478bd9Sstevel@tonic-gate sm_dprintf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n", 282*058561cbSjbeck host, errno, h_errno); 2837c478bd9Sstevel@tonic-gate switch (h_errno) 2847c478bd9Sstevel@tonic-gate { 2857c478bd9Sstevel@tonic-gate case NO_DATA: 2867c478bd9Sstevel@tonic-gate trycanon = true; 2877c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate case NO_RECOVERY: 2907c478bd9Sstevel@tonic-gate /* no MX data on this host */ 2917c478bd9Sstevel@tonic-gate goto punt; 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate case HOST_NOT_FOUND: 2947c478bd9Sstevel@tonic-gate # if BROKEN_RES_SEARCH 2957c478bd9Sstevel@tonic-gate case 0: /* Ultrix resolver retns failure w/ h_errno=0 */ 2967c478bd9Sstevel@tonic-gate # endif /* BROKEN_RES_SEARCH */ 2977c478bd9Sstevel@tonic-gate /* host doesn't exist in DNS; might be in /etc/hosts */ 2987c478bd9Sstevel@tonic-gate trycanon = true; 2997c478bd9Sstevel@tonic-gate *rcode = EX_NOHOST; 3007c478bd9Sstevel@tonic-gate goto punt; 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate case TRY_AGAIN: 3037c478bd9Sstevel@tonic-gate case -1: 3047c478bd9Sstevel@tonic-gate /* couldn't connect to the name server */ 3057c478bd9Sstevel@tonic-gate if (fallbackMX != NULL) 3067c478bd9Sstevel@tonic-gate { 3077c478bd9Sstevel@tonic-gate /* name server is hosed -- push to fallback */ 3087c478bd9Sstevel@tonic-gate return fallbackmxrr(nmx, prefs, mxhosts); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate /* it might come up later; better queue it up */ 3117c478bd9Sstevel@tonic-gate *rcode = EX_TEMPFAIL; 3127c478bd9Sstevel@tonic-gate break; 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate default: 3157c478bd9Sstevel@tonic-gate syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)", 3167c478bd9Sstevel@tonic-gate host, h_errno); 3177c478bd9Sstevel@tonic-gate *rcode = EX_OSERR; 3187c478bd9Sstevel@tonic-gate break; 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* irreconcilable differences */ 3227c478bd9Sstevel@tonic-gate return -1; 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate /* avoid problems after truncation in tcp packets */ 3267c478bd9Sstevel@tonic-gate if (n > sizeof(answer)) 3277c478bd9Sstevel@tonic-gate n = sizeof(answer); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* find first satisfactory answer */ 3307c478bd9Sstevel@tonic-gate hp = (HEADER *)&answer; 3317c478bd9Sstevel@tonic-gate cp = (unsigned char *)&answer + HFIXEDSZ; 3327c478bd9Sstevel@tonic-gate eom = (unsigned char *)&answer + n; 3337c478bd9Sstevel@tonic-gate for (qdcount = ntohs((unsigned short) hp->qdcount); 3347c478bd9Sstevel@tonic-gate qdcount--; 3357c478bd9Sstevel@tonic-gate cp += n + QFIXEDSZ) 3367c478bd9Sstevel@tonic-gate { 3377c478bd9Sstevel@tonic-gate if ((n = dn_skipname(cp, eom)) < 0) 3387c478bd9Sstevel@tonic-gate goto punt; 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* NOTE: see definition of MXHostBuf! */ 3427c478bd9Sstevel@tonic-gate buflen = sizeof(MXHostBuf) - 1; 3437c478bd9Sstevel@tonic-gate SM_ASSERT(buflen > 0); 3447c478bd9Sstevel@tonic-gate bp = MXHostBuf; 3457c478bd9Sstevel@tonic-gate ancount = ntohs((unsigned short) hp->ancount); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* See RFC 1035 for layout of RRs. */ 3487c478bd9Sstevel@tonic-gate /* XXX leave room for FallbackMX ? */ 3497c478bd9Sstevel@tonic-gate while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1) 3507c478bd9Sstevel@tonic-gate { 3517c478bd9Sstevel@tonic-gate if ((n = dn_expand((unsigned char *)&answer, eom, cp, 3527c478bd9Sstevel@tonic-gate (RES_UNC_T) bp, buflen)) < 0) 3537c478bd9Sstevel@tonic-gate break; 3547c478bd9Sstevel@tonic-gate cp += n; 3557c478bd9Sstevel@tonic-gate GETSHORT(type, cp); 3567c478bd9Sstevel@tonic-gate cp += INT16SZ; /* skip over class */ 3577c478bd9Sstevel@tonic-gate GETLONG(ttl, cp); 3587c478bd9Sstevel@tonic-gate GETSHORT(n, cp); /* rdlength */ 3597c478bd9Sstevel@tonic-gate if (type != T_MX) 3607c478bd9Sstevel@tonic-gate { 3617c478bd9Sstevel@tonic-gate if (tTd(8, 8) || _res.options & RES_DEBUG) 3627c478bd9Sstevel@tonic-gate sm_dprintf("unexpected answer type %d, size %d\n", 3637c478bd9Sstevel@tonic-gate type, n); 3647c478bd9Sstevel@tonic-gate cp += n; 3657c478bd9Sstevel@tonic-gate continue; 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate GETSHORT(pref, cp); 3687c478bd9Sstevel@tonic-gate if ((n = dn_expand((unsigned char *)&answer, eom, cp, 3697c478bd9Sstevel@tonic-gate (RES_UNC_T) bp, buflen)) < 0) 3707c478bd9Sstevel@tonic-gate break; 3717c478bd9Sstevel@tonic-gate cp += n; 3727c478bd9Sstevel@tonic-gate n = strlen(bp); 3737c478bd9Sstevel@tonic-gate # if 0 3747c478bd9Sstevel@tonic-gate /* Can this happen? */ 3757c478bd9Sstevel@tonic-gate if (n == 0) 3767c478bd9Sstevel@tonic-gate { 3777c478bd9Sstevel@tonic-gate if (LogLevel > 4) 3787c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 3797c478bd9Sstevel@tonic-gate "MX records for %s contain empty string", 3807c478bd9Sstevel@tonic-gate host); 3817c478bd9Sstevel@tonic-gate continue; 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate # endif /* 0 */ 3847c478bd9Sstevel@tonic-gate if (wordinclass(bp, 'w')) 3857c478bd9Sstevel@tonic-gate { 3867c478bd9Sstevel@tonic-gate if (tTd(8, 3)) 3877c478bd9Sstevel@tonic-gate sm_dprintf("found localhost (%s) in MX list, pref=%d\n", 3887c478bd9Sstevel@tonic-gate bp, pref); 3897c478bd9Sstevel@tonic-gate if (droplocalhost) 3907c478bd9Sstevel@tonic-gate { 3917c478bd9Sstevel@tonic-gate if (!seenlocal || pref < localpref) 3927c478bd9Sstevel@tonic-gate localpref = pref; 3937c478bd9Sstevel@tonic-gate seenlocal = true; 3947c478bd9Sstevel@tonic-gate continue; 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate weight[nmx] = 0; 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate else 3997c478bd9Sstevel@tonic-gate weight[nmx] = mxrand(bp); 4007c478bd9Sstevel@tonic-gate prefs[nmx] = pref; 4017c478bd9Sstevel@tonic-gate mxhosts[nmx++] = bp; 4027c478bd9Sstevel@tonic-gate bp += n; 4037c478bd9Sstevel@tonic-gate if (bp[-1] != '.') 4047c478bd9Sstevel@tonic-gate { 4057c478bd9Sstevel@tonic-gate *bp++ = '.'; 4067c478bd9Sstevel@tonic-gate n++; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate *bp++ = '\0'; 4097c478bd9Sstevel@tonic-gate if (buflen < n + 1) 4107c478bd9Sstevel@tonic-gate { 4117c478bd9Sstevel@tonic-gate /* don't want to wrap buflen */ 4127c478bd9Sstevel@tonic-gate break; 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate buflen -= n + 1; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* return only one TTL entry, that should be sufficient */ 4187c478bd9Sstevel@tonic-gate if (ttl > 0 && pttl != NULL) 4197c478bd9Sstevel@tonic-gate *pttl = ttl; 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate /* sort the records */ 4227c478bd9Sstevel@tonic-gate for (i = 0; i < nmx; i++) 4237c478bd9Sstevel@tonic-gate { 4247c478bd9Sstevel@tonic-gate for (j = i + 1; j < nmx; j++) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate if (prefs[i] > prefs[j] || 4277c478bd9Sstevel@tonic-gate (prefs[i] == prefs[j] && weight[i] > weight[j])) 4287c478bd9Sstevel@tonic-gate { 4297c478bd9Sstevel@tonic-gate register int temp; 4307c478bd9Sstevel@tonic-gate register char *temp1; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate temp = prefs[i]; 4337c478bd9Sstevel@tonic-gate prefs[i] = prefs[j]; 4347c478bd9Sstevel@tonic-gate prefs[j] = temp; 4357c478bd9Sstevel@tonic-gate temp1 = mxhosts[i]; 4367c478bd9Sstevel@tonic-gate mxhosts[i] = mxhosts[j]; 4377c478bd9Sstevel@tonic-gate mxhosts[j] = temp1; 4387c478bd9Sstevel@tonic-gate temp = weight[i]; 4397c478bd9Sstevel@tonic-gate weight[i] = weight[j]; 4407c478bd9Sstevel@tonic-gate weight[j] = temp; 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate if (seenlocal && prefs[i] >= localpref) 4447c478bd9Sstevel@tonic-gate { 4457c478bd9Sstevel@tonic-gate /* truncate higher preference part of list */ 4467c478bd9Sstevel@tonic-gate nmx = i; 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate /* delete duplicates from list (yes, some bozos have duplicates) */ 4517c478bd9Sstevel@tonic-gate for (i = 0; i < nmx - 1; ) 4527c478bd9Sstevel@tonic-gate { 4537c478bd9Sstevel@tonic-gate if (sm_strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0) 4547c478bd9Sstevel@tonic-gate i++; 4557c478bd9Sstevel@tonic-gate else 4567c478bd9Sstevel@tonic-gate { 4577c478bd9Sstevel@tonic-gate /* compress out duplicate */ 4587c478bd9Sstevel@tonic-gate for (j = i + 1; j < nmx; j++) 4597c478bd9Sstevel@tonic-gate { 4607c478bd9Sstevel@tonic-gate mxhosts[j] = mxhosts[j + 1]; 4617c478bd9Sstevel@tonic-gate prefs[j] = prefs[j + 1]; 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate nmx--; 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if (nmx == 0) 4687c478bd9Sstevel@tonic-gate { 4697c478bd9Sstevel@tonic-gate punt: 4707c478bd9Sstevel@tonic-gate if (seenlocal) 4717c478bd9Sstevel@tonic-gate { 4727c478bd9Sstevel@tonic-gate struct hostent *h = NULL; 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate /* 4757c478bd9Sstevel@tonic-gate ** If we have deleted all MX entries, this is 4767c478bd9Sstevel@tonic-gate ** an error -- we should NEVER send to a host that 4777c478bd9Sstevel@tonic-gate ** has an MX, and this should have been caught 4787c478bd9Sstevel@tonic-gate ** earlier in the config file. 4797c478bd9Sstevel@tonic-gate ** 4807c478bd9Sstevel@tonic-gate ** Some sites prefer to go ahead and try the 4817c478bd9Sstevel@tonic-gate ** A record anyway; that case is handled by 4827c478bd9Sstevel@tonic-gate ** setting TryNullMXList. I believe this is a 4837c478bd9Sstevel@tonic-gate ** bad idea, but it's up to you.... 4847c478bd9Sstevel@tonic-gate */ 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate if (TryNullMXList) 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate SM_SET_H_ERRNO(0); 4897c478bd9Sstevel@tonic-gate errno = 0; 4907c478bd9Sstevel@tonic-gate h = sm_gethostbyname(host, AF_INET); 4917c478bd9Sstevel@tonic-gate if (h == NULL) 4927c478bd9Sstevel@tonic-gate { 4937c478bd9Sstevel@tonic-gate if (errno == ETIMEDOUT || 4947c478bd9Sstevel@tonic-gate h_errno == TRY_AGAIN || 4957c478bd9Sstevel@tonic-gate (errno == ECONNREFUSED && 4967c478bd9Sstevel@tonic-gate UseNameServer)) 4977c478bd9Sstevel@tonic-gate { 4987c478bd9Sstevel@tonic-gate *rcode = EX_TEMPFAIL; 4997c478bd9Sstevel@tonic-gate return -1; 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate # if NETINET6 5027c478bd9Sstevel@tonic-gate SM_SET_H_ERRNO(0); 5037c478bd9Sstevel@tonic-gate errno = 0; 5047c478bd9Sstevel@tonic-gate h = sm_gethostbyname(host, AF_INET6); 5057c478bd9Sstevel@tonic-gate if (h == NULL && 5067c478bd9Sstevel@tonic-gate (errno == ETIMEDOUT || 5077c478bd9Sstevel@tonic-gate h_errno == TRY_AGAIN || 5087c478bd9Sstevel@tonic-gate (errno == ECONNREFUSED && 5097c478bd9Sstevel@tonic-gate UseNameServer))) 5107c478bd9Sstevel@tonic-gate { 5117c478bd9Sstevel@tonic-gate *rcode = EX_TEMPFAIL; 5127c478bd9Sstevel@tonic-gate return -1; 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate if (h == NULL) 5197c478bd9Sstevel@tonic-gate { 5207c478bd9Sstevel@tonic-gate *rcode = EX_CONFIG; 5217c478bd9Sstevel@tonic-gate syserr("MX list for %s points back to %s", 5227c478bd9Sstevel@tonic-gate host, MyHostName); 5237c478bd9Sstevel@tonic-gate return -1; 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate # if NETINET6 5267c478bd9Sstevel@tonic-gate freehostent(h); 5273ee0e492Sjbeck h = NULL; 5287c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 5297c478bd9Sstevel@tonic-gate } 530*058561cbSjbeck if (strlen(host) >= sizeof(MXHostBuf)) 5317c478bd9Sstevel@tonic-gate { 5327c478bd9Sstevel@tonic-gate *rcode = EX_CONFIG; 5337c478bd9Sstevel@tonic-gate syserr("Host name %s too long", 5347c478bd9Sstevel@tonic-gate shortenstring(host, MAXSHORTSTR)); 5357c478bd9Sstevel@tonic-gate return -1; 5367c478bd9Sstevel@tonic-gate } 537*058561cbSjbeck (void) sm_strlcpy(MXHostBuf, host, sizeof(MXHostBuf)); 5387c478bd9Sstevel@tonic-gate mxhosts[0] = MXHostBuf; 5397c478bd9Sstevel@tonic-gate prefs[0] = 0; 5407c478bd9Sstevel@tonic-gate if (host[0] == '[') 5417c478bd9Sstevel@tonic-gate { 5427c478bd9Sstevel@tonic-gate register char *p; 5437c478bd9Sstevel@tonic-gate # if NETINET6 5447c478bd9Sstevel@tonic-gate struct sockaddr_in6 tmp6; 5457c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate /* this may be an MX suppression-style address */ 5487c478bd9Sstevel@tonic-gate p = strchr(MXHostBuf, ']'); 5497c478bd9Sstevel@tonic-gate if (p != NULL) 5507c478bd9Sstevel@tonic-gate { 5517c478bd9Sstevel@tonic-gate *p = '\0'; 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate if (inet_addr(&MXHostBuf[1]) != INADDR_NONE) 5547c478bd9Sstevel@tonic-gate { 5557c478bd9Sstevel@tonic-gate nmx++; 5567c478bd9Sstevel@tonic-gate *p = ']'; 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate # if NETINET6 5597c478bd9Sstevel@tonic-gate else if (anynet_pton(AF_INET6, &MXHostBuf[1], 5607c478bd9Sstevel@tonic-gate &tmp6.sin6_addr) == 1) 5617c478bd9Sstevel@tonic-gate { 5627c478bd9Sstevel@tonic-gate nmx++; 5637c478bd9Sstevel@tonic-gate *p = ']'; 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 5667c478bd9Sstevel@tonic-gate else 5677c478bd9Sstevel@tonic-gate { 5687c478bd9Sstevel@tonic-gate trycanon = true; 5697c478bd9Sstevel@tonic-gate mxhosts[0]++; 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate if (trycanon && 574*058561cbSjbeck getcanonname(mxhosts[0], sizeof(MXHostBuf) - 2, false, pttl)) 5757c478bd9Sstevel@tonic-gate { 5767c478bd9Sstevel@tonic-gate /* XXX MXHostBuf == "" ? is that possible? */ 5777c478bd9Sstevel@tonic-gate bp = &MXHostBuf[strlen(MXHostBuf)]; 5787c478bd9Sstevel@tonic-gate if (bp[-1] != '.') 5797c478bd9Sstevel@tonic-gate { 5807c478bd9Sstevel@tonic-gate *bp++ = '.'; 5817c478bd9Sstevel@tonic-gate *bp = '\0'; 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate nmx = 1; 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* if we have a default lowest preference, include that */ 5887c478bd9Sstevel@tonic-gate if (fallbackMX != NULL && !seenlocal) 5897c478bd9Sstevel@tonic-gate { 5907c478bd9Sstevel@tonic-gate nmx = fallbackmxrr(nmx, prefs, mxhosts); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate return nmx; 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate /* 5957c478bd9Sstevel@tonic-gate ** MXRAND -- create a randomizer for equal MX preferences 5967c478bd9Sstevel@tonic-gate ** 5977c478bd9Sstevel@tonic-gate ** If two MX hosts have equal preferences we want to randomize 5987c478bd9Sstevel@tonic-gate ** the selection. But in order for signatures to be the same, 5997c478bd9Sstevel@tonic-gate ** we need to randomize the same way each time. This function 6007c478bd9Sstevel@tonic-gate ** computes a pseudo-random hash function from the host name. 6017c478bd9Sstevel@tonic-gate ** 6027c478bd9Sstevel@tonic-gate ** Parameters: 6037c478bd9Sstevel@tonic-gate ** host -- the name of the host. 6047c478bd9Sstevel@tonic-gate ** 6057c478bd9Sstevel@tonic-gate ** Returns: 6067c478bd9Sstevel@tonic-gate ** A random but repeatable value based on the host name. 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate static int 6107c478bd9Sstevel@tonic-gate mxrand(host) 6117c478bd9Sstevel@tonic-gate register char *host; 6127c478bd9Sstevel@tonic-gate { 6137c478bd9Sstevel@tonic-gate int hfunc; 6147c478bd9Sstevel@tonic-gate static unsigned int seed; 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate if (seed == 0) 6177c478bd9Sstevel@tonic-gate { 6187c478bd9Sstevel@tonic-gate seed = (int) curtime() & 0xffff; 6197c478bd9Sstevel@tonic-gate if (seed == 0) 6207c478bd9Sstevel@tonic-gate seed++; 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate if (tTd(17, 9)) 6247c478bd9Sstevel@tonic-gate sm_dprintf("mxrand(%s)", host); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate hfunc = seed; 6277c478bd9Sstevel@tonic-gate while (*host != '\0') 6287c478bd9Sstevel@tonic-gate { 6297c478bd9Sstevel@tonic-gate int c = *host++; 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate if (isascii(c) && isupper(c)) 6327c478bd9Sstevel@tonic-gate c = tolower(c); 6337c478bd9Sstevel@tonic-gate hfunc = ((hfunc << 1) ^ c) % 2003; 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate hfunc &= 0xff; 6377c478bd9Sstevel@tonic-gate hfunc++; 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate if (tTd(17, 9)) 6407c478bd9Sstevel@tonic-gate sm_dprintf(" = %d\n", hfunc); 6417c478bd9Sstevel@tonic-gate return hfunc; 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate /* 6447c478bd9Sstevel@tonic-gate ** BESTMX -- find the best MX for a name 6457c478bd9Sstevel@tonic-gate ** 6467c478bd9Sstevel@tonic-gate ** This is really a hack, but I don't see any obvious way 6477c478bd9Sstevel@tonic-gate ** to generalize it at the moment. 6487c478bd9Sstevel@tonic-gate */ 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate /* ARGSUSED3 */ 6517c478bd9Sstevel@tonic-gate char * 6527c478bd9Sstevel@tonic-gate bestmx_map_lookup(map, name, av, statp) 6537c478bd9Sstevel@tonic-gate MAP *map; 6547c478bd9Sstevel@tonic-gate char *name; 6557c478bd9Sstevel@tonic-gate char **av; 6567c478bd9Sstevel@tonic-gate int *statp; 6577c478bd9Sstevel@tonic-gate { 6587c478bd9Sstevel@tonic-gate int nmx; 6597c478bd9Sstevel@tonic-gate int saveopts = _res.options; 6607c478bd9Sstevel@tonic-gate int i; 6617c478bd9Sstevel@tonic-gate ssize_t len = 0; 6627c478bd9Sstevel@tonic-gate char *result; 6637c478bd9Sstevel@tonic-gate char *mxhosts[MAXMXHOSTS + 1]; 6647c478bd9Sstevel@tonic-gate #if _FFR_BESTMX_BETTER_TRUNCATION 6657c478bd9Sstevel@tonic-gate char *buf; 6667c478bd9Sstevel@tonic-gate #else /* _FFR_BESTMX_BETTER_TRUNCATION */ 6677c478bd9Sstevel@tonic-gate char *p; 6687c478bd9Sstevel@tonic-gate char buf[PSBUFSIZE / 2]; 6697c478bd9Sstevel@tonic-gate #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate _res.options &= ~(RES_DNSRCH|RES_DEFNAMES); 6727c478bd9Sstevel@tonic-gate nmx = getmxrr(name, mxhosts, NULL, false, statp, false, NULL); 6737c478bd9Sstevel@tonic-gate _res.options = saveopts; 6747c478bd9Sstevel@tonic-gate if (nmx <= 0) 6757c478bd9Sstevel@tonic-gate return NULL; 6767c478bd9Sstevel@tonic-gate if (bitset(MF_MATCHONLY, map->map_mflags)) 6777c478bd9Sstevel@tonic-gate return map_rewrite(map, name, strlen(name), NULL); 6787c478bd9Sstevel@tonic-gate if ((map->map_coldelim == '\0') || (nmx == 1)) 6797c478bd9Sstevel@tonic-gate return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av); 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* 6827c478bd9Sstevel@tonic-gate ** We were given a -z flag (return all MXs) and there are multiple 6837c478bd9Sstevel@tonic-gate ** ones. We need to build them all into a list. 6847c478bd9Sstevel@tonic-gate */ 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate #if _FFR_BESTMX_BETTER_TRUNCATION 6877c478bd9Sstevel@tonic-gate for (i = 0; i < nmx; i++) 6887c478bd9Sstevel@tonic-gate { 6897c478bd9Sstevel@tonic-gate if (strchr(mxhosts[i], map->map_coldelim) != NULL) 6907c478bd9Sstevel@tonic-gate { 6917c478bd9Sstevel@tonic-gate syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 6927c478bd9Sstevel@tonic-gate mxhosts[i], map->map_coldelim); 6937c478bd9Sstevel@tonic-gate return NULL; 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate len += strlen(mxhosts[i]) + 1; 6967c478bd9Sstevel@tonic-gate if (len < 0) 6977c478bd9Sstevel@tonic-gate { 6987c478bd9Sstevel@tonic-gate len -= strlen(mxhosts[i]) + 1; 6997c478bd9Sstevel@tonic-gate break; 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate buf = (char *) sm_malloc(len); 7037c478bd9Sstevel@tonic-gate if (buf == NULL) 7047c478bd9Sstevel@tonic-gate { 7057c478bd9Sstevel@tonic-gate *statp = EX_UNAVAILABLE; 7067c478bd9Sstevel@tonic-gate return NULL; 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate *buf = '\0'; 7097c478bd9Sstevel@tonic-gate for (i = 0; i < nmx; i++) 7107c478bd9Sstevel@tonic-gate { 7117c478bd9Sstevel@tonic-gate int end; 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate end = sm_strlcat(buf, mxhosts[i], len); 7147c478bd9Sstevel@tonic-gate if (i != nmx && end + 1 < len) 7157c478bd9Sstevel@tonic-gate { 7167c478bd9Sstevel@tonic-gate buf[end] = map->map_coldelim; 7177c478bd9Sstevel@tonic-gate buf[end + 1] = '\0'; 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate /* Cleanly truncate for rulesets */ 7227c478bd9Sstevel@tonic-gate truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim); 7237c478bd9Sstevel@tonic-gate #else /* _FFR_BESTMX_BETTER_TRUNCATION */ 7247c478bd9Sstevel@tonic-gate p = buf; 7257c478bd9Sstevel@tonic-gate for (i = 0; i < nmx; i++) 7267c478bd9Sstevel@tonic-gate { 7277c478bd9Sstevel@tonic-gate size_t slen; 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate if (strchr(mxhosts[i], map->map_coldelim) != NULL) 7307c478bd9Sstevel@tonic-gate { 7317c478bd9Sstevel@tonic-gate syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X", 7327c478bd9Sstevel@tonic-gate mxhosts[i], map->map_coldelim); 7337c478bd9Sstevel@tonic-gate return NULL; 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate slen = strlen(mxhosts[i]); 736*058561cbSjbeck if (len + slen + 2 > sizeof(buf)) 7377c478bd9Sstevel@tonic-gate break; 7387c478bd9Sstevel@tonic-gate if (i > 0) 7397c478bd9Sstevel@tonic-gate { 7407c478bd9Sstevel@tonic-gate *p++ = map->map_coldelim; 7417c478bd9Sstevel@tonic-gate len++; 7427c478bd9Sstevel@tonic-gate } 743*058561cbSjbeck (void) sm_strlcpy(p, mxhosts[i], sizeof(buf) - len); 7447c478bd9Sstevel@tonic-gate p += slen; 7457c478bd9Sstevel@tonic-gate len += slen; 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate result = map_rewrite(map, buf, len, av); 7507c478bd9Sstevel@tonic-gate #if _FFR_BESTMX_BETTER_TRUNCATION 7517c478bd9Sstevel@tonic-gate sm_free(buf); 7527c478bd9Sstevel@tonic-gate #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 7537c478bd9Sstevel@tonic-gate return result; 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate /* 7567c478bd9Sstevel@tonic-gate ** DNS_GETCANONNAME -- get the canonical name for named host using DNS 7577c478bd9Sstevel@tonic-gate ** 7587c478bd9Sstevel@tonic-gate ** This algorithm tries to be smart about wildcard MX records. 7597c478bd9Sstevel@tonic-gate ** This is hard to do because DNS doesn't tell is if we matched 7607c478bd9Sstevel@tonic-gate ** against a wildcard or a specific MX. 7617c478bd9Sstevel@tonic-gate ** 7627c478bd9Sstevel@tonic-gate ** We always prefer A & CNAME records, since these are presumed 7637c478bd9Sstevel@tonic-gate ** to be specific. 7647c478bd9Sstevel@tonic-gate ** 7657c478bd9Sstevel@tonic-gate ** If we match an MX in one pass and lose it in the next, we use 7667c478bd9Sstevel@tonic-gate ** the old one. For example, consider an MX matching *.FOO.BAR.COM. 7677c478bd9Sstevel@tonic-gate ** A hostname bletch.foo.bar.com will match against this MX, but 7687c478bd9Sstevel@tonic-gate ** will stop matching when we try bletch.bar.com -- so we know 7697c478bd9Sstevel@tonic-gate ** that bletch.foo.bar.com must have been right. This fails if 7707c478bd9Sstevel@tonic-gate ** there was also an MX record matching *.BAR.COM, but there are 7717c478bd9Sstevel@tonic-gate ** some things that just can't be fixed. 7727c478bd9Sstevel@tonic-gate ** 7737c478bd9Sstevel@tonic-gate ** Parameters: 7747c478bd9Sstevel@tonic-gate ** host -- a buffer containing the name of the host. 7757c478bd9Sstevel@tonic-gate ** This is a value-result parameter. 7767c478bd9Sstevel@tonic-gate ** hbsize -- the size of the host buffer. 7777c478bd9Sstevel@tonic-gate ** trymx -- if set, try MX records as well as A and CNAME. 7787c478bd9Sstevel@tonic-gate ** statp -- pointer to place to store status. 7797c478bd9Sstevel@tonic-gate ** pttl -- pointer to return TTL (can be NULL). 7807c478bd9Sstevel@tonic-gate ** 7817c478bd9Sstevel@tonic-gate ** Returns: 7827c478bd9Sstevel@tonic-gate ** true -- if the host matched. 7837c478bd9Sstevel@tonic-gate ** false -- otherwise. 7847c478bd9Sstevel@tonic-gate */ 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate bool 7877c478bd9Sstevel@tonic-gate dns_getcanonname(host, hbsize, trymx, statp, pttl) 7887c478bd9Sstevel@tonic-gate char *host; 7897c478bd9Sstevel@tonic-gate int hbsize; 7907c478bd9Sstevel@tonic-gate bool trymx; 7917c478bd9Sstevel@tonic-gate int *statp; 7927c478bd9Sstevel@tonic-gate int *pttl; 7937c478bd9Sstevel@tonic-gate { 7947c478bd9Sstevel@tonic-gate register unsigned char *eom, *ap; 7957c478bd9Sstevel@tonic-gate register char *cp; 7967c478bd9Sstevel@tonic-gate register int n; 7977c478bd9Sstevel@tonic-gate HEADER *hp; 7987c478bd9Sstevel@tonic-gate querybuf answer; 7997c478bd9Sstevel@tonic-gate int ancount, qdcount; 8007c478bd9Sstevel@tonic-gate int ret; 8017c478bd9Sstevel@tonic-gate char **domain; 8027c478bd9Sstevel@tonic-gate int type; 8037c478bd9Sstevel@tonic-gate int ttl = 0; 8047c478bd9Sstevel@tonic-gate char **dp; 8057c478bd9Sstevel@tonic-gate char *mxmatch; 8067c478bd9Sstevel@tonic-gate bool amatch; 8077c478bd9Sstevel@tonic-gate bool gotmx = false; 8087c478bd9Sstevel@tonic-gate int qtype; 8097c478bd9Sstevel@tonic-gate int initial; 8107c478bd9Sstevel@tonic-gate int loopcnt; 8117c478bd9Sstevel@tonic-gate char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)]; 8127c478bd9Sstevel@tonic-gate char *searchlist[MAXDNSRCH + 2]; 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate if (tTd(8, 2)) 8157c478bd9Sstevel@tonic-gate sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx); 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate if ((_res.options & RES_INIT) == 0 && res_init() == -1) 8187c478bd9Sstevel@tonic-gate { 8197c478bd9Sstevel@tonic-gate *statp = EX_UNAVAILABLE; 8207c478bd9Sstevel@tonic-gate return false; 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate *statp = EX_OK; 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate ** Initialize domain search list. If there is at least one 8277c478bd9Sstevel@tonic-gate ** dot in the name, search the unmodified name first so we 8287c478bd9Sstevel@tonic-gate ** find "vse.CS" in Czechoslovakia instead of in the local 8297c478bd9Sstevel@tonic-gate ** domain (e.g., vse.CS.Berkeley.EDU). Note that there is no 8307c478bd9Sstevel@tonic-gate ** longer a country named Czechoslovakia but this type of problem 8317c478bd9Sstevel@tonic-gate ** is still present. 8327c478bd9Sstevel@tonic-gate ** 8337c478bd9Sstevel@tonic-gate ** Older versions of the resolver could create this 8347c478bd9Sstevel@tonic-gate ** list by tearing apart the host name. 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate loopcnt = 0; 8387c478bd9Sstevel@tonic-gate cnameloop: 8397c478bd9Sstevel@tonic-gate /* Check for dots in the name */ 8407c478bd9Sstevel@tonic-gate for (cp = host, n = 0; *cp != '\0'; cp++) 8417c478bd9Sstevel@tonic-gate if (*cp == '.') 8427c478bd9Sstevel@tonic-gate n++; 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate /* 8457c478bd9Sstevel@tonic-gate ** Build the search list. 8467c478bd9Sstevel@tonic-gate ** If there is at least one dot in name, start with a null 8477c478bd9Sstevel@tonic-gate ** domain to search the unmodified name first. 8487c478bd9Sstevel@tonic-gate ** If name does not end with a dot and search up local domain 8497c478bd9Sstevel@tonic-gate ** tree desired, append each local domain component to the 8507c478bd9Sstevel@tonic-gate ** search list; if name contains no dots and default domain 8517c478bd9Sstevel@tonic-gate ** name is desired, append default domain name to search list; 8527c478bd9Sstevel@tonic-gate ** else if name ends in a dot, remove that dot. 8537c478bd9Sstevel@tonic-gate */ 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate dp = searchlist; 8567c478bd9Sstevel@tonic-gate if (n > 0) 8577c478bd9Sstevel@tonic-gate *dp++ = ""; 8587c478bd9Sstevel@tonic-gate if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options)) 8597c478bd9Sstevel@tonic-gate { 8607c478bd9Sstevel@tonic-gate /* make sure there are less than MAXDNSRCH domains */ 8617c478bd9Sstevel@tonic-gate for (domain = RES_DNSRCH_VARIABLE, ret = 0; 8627c478bd9Sstevel@tonic-gate *domain != NULL && ret < MAXDNSRCH; 8637c478bd9Sstevel@tonic-gate ret++) 8647c478bd9Sstevel@tonic-gate *dp++ = *domain++; 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate else if (n == 0 && bitset(RES_DEFNAMES, _res.options)) 8677c478bd9Sstevel@tonic-gate { 8687c478bd9Sstevel@tonic-gate *dp++ = _res.defdname; 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate else if (*cp == '.') 8717c478bd9Sstevel@tonic-gate { 8727c478bd9Sstevel@tonic-gate *cp = '\0'; 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate *dp = NULL; 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate /* 8777c478bd9Sstevel@tonic-gate ** Now loop through the search list, appending each domain in turn 8787c478bd9Sstevel@tonic-gate ** name and searching for a match. 8797c478bd9Sstevel@tonic-gate */ 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate mxmatch = NULL; 8827c478bd9Sstevel@tonic-gate initial = T_A; 8837c478bd9Sstevel@tonic-gate # if NETINET6 8847c478bd9Sstevel@tonic-gate if (InetMode == AF_INET6) 8857c478bd9Sstevel@tonic-gate initial = T_AAAA; 8867c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 8877c478bd9Sstevel@tonic-gate qtype = initial; 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate for (dp = searchlist; *dp != NULL; ) 8907c478bd9Sstevel@tonic-gate { 8917c478bd9Sstevel@tonic-gate if (qtype == initial) 8927c478bd9Sstevel@tonic-gate gotmx = false; 8937c478bd9Sstevel@tonic-gate if (tTd(8, 5)) 8947c478bd9Sstevel@tonic-gate sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n", 8957c478bd9Sstevel@tonic-gate host, *dp, 8967c478bd9Sstevel@tonic-gate # if NETINET6 8977c478bd9Sstevel@tonic-gate qtype == T_AAAA ? "AAAA" : 8987c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 8997c478bd9Sstevel@tonic-gate qtype == T_A ? "A" : 9007c478bd9Sstevel@tonic-gate qtype == T_MX ? "MX" : 9017c478bd9Sstevel@tonic-gate "???"); 9027c478bd9Sstevel@tonic-gate errno = 0; 9037c478bd9Sstevel@tonic-gate ret = res_querydomain(host, *dp, C_IN, qtype, 9047c478bd9Sstevel@tonic-gate answer.qb2, sizeof(answer.qb2)); 9057c478bd9Sstevel@tonic-gate if (ret <= 0) 9067c478bd9Sstevel@tonic-gate { 9077c478bd9Sstevel@tonic-gate int save_errno = errno; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate if (tTd(8, 7)) 9107c478bd9Sstevel@tonic-gate sm_dprintf("\tNO: errno=%d, h_errno=%d\n", 9117c478bd9Sstevel@tonic-gate save_errno, h_errno); 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN) 9147c478bd9Sstevel@tonic-gate { 9157c478bd9Sstevel@tonic-gate /* 9167c478bd9Sstevel@tonic-gate ** the name server seems to be down or broken. 9177c478bd9Sstevel@tonic-gate */ 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate SM_SET_H_ERRNO(TRY_AGAIN); 9207c478bd9Sstevel@tonic-gate if (**dp == '\0') 9217c478bd9Sstevel@tonic-gate { 9227c478bd9Sstevel@tonic-gate if (*statp == EX_OK) 9237c478bd9Sstevel@tonic-gate *statp = EX_TEMPFAIL; 9247c478bd9Sstevel@tonic-gate goto nexttype; 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate *statp = EX_TEMPFAIL; 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate if (WorkAroundBrokenAAAA) 9297c478bd9Sstevel@tonic-gate { 9307c478bd9Sstevel@tonic-gate /* 9317c478bd9Sstevel@tonic-gate ** Only return if not TRY_AGAIN as an 9327c478bd9Sstevel@tonic-gate ** attempt with a different qtype may 9337c478bd9Sstevel@tonic-gate ** succeed (res_querydomain() calls 9347c478bd9Sstevel@tonic-gate ** res_query() calls res_send() which 9357c478bd9Sstevel@tonic-gate ** sets errno to ETIMEDOUT if the 9367c478bd9Sstevel@tonic-gate ** nameservers could be contacted but 9377c478bd9Sstevel@tonic-gate ** didn't give an answer). 9387c478bd9Sstevel@tonic-gate */ 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate if (save_errno != ETIMEDOUT) 9417c478bd9Sstevel@tonic-gate return false; 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate else 9447c478bd9Sstevel@tonic-gate return false; 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate nexttype: 9487c478bd9Sstevel@tonic-gate if (h_errno != HOST_NOT_FOUND) 9497c478bd9Sstevel@tonic-gate { 9507c478bd9Sstevel@tonic-gate /* might have another type of interest */ 9517c478bd9Sstevel@tonic-gate # if NETINET6 9527c478bd9Sstevel@tonic-gate if (qtype == T_AAAA) 9537c478bd9Sstevel@tonic-gate { 9547c478bd9Sstevel@tonic-gate qtype = T_A; 9557c478bd9Sstevel@tonic-gate continue; 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate else 9587c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 9597c478bd9Sstevel@tonic-gate if (qtype == T_A && !gotmx && 9607c478bd9Sstevel@tonic-gate (trymx || **dp == '\0')) 9617c478bd9Sstevel@tonic-gate { 9627c478bd9Sstevel@tonic-gate qtype = T_MX; 9637c478bd9Sstevel@tonic-gate continue; 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate /* definite no -- try the next domain */ 9687c478bd9Sstevel@tonic-gate dp++; 9697c478bd9Sstevel@tonic-gate qtype = initial; 9707c478bd9Sstevel@tonic-gate continue; 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate else if (tTd(8, 7)) 9737c478bd9Sstevel@tonic-gate sm_dprintf("\tYES\n"); 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate /* avoid problems after truncation in tcp packets */ 9767c478bd9Sstevel@tonic-gate if (ret > sizeof(answer)) 9777c478bd9Sstevel@tonic-gate ret = sizeof(answer); 9783ee0e492Sjbeck SM_ASSERT(ret >= 0); 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate /* 9817c478bd9Sstevel@tonic-gate ** Appear to have a match. Confirm it by searching for A or 9827c478bd9Sstevel@tonic-gate ** CNAME records. If we don't have a local domain 9837c478bd9Sstevel@tonic-gate ** wild card MX record, we will accept MX as well. 9847c478bd9Sstevel@tonic-gate */ 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate hp = (HEADER *) &answer; 9877c478bd9Sstevel@tonic-gate ap = (unsigned char *) &answer + HFIXEDSZ; 9887c478bd9Sstevel@tonic-gate eom = (unsigned char *) &answer + ret; 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /* skip question part of response -- we know what we asked */ 9917c478bd9Sstevel@tonic-gate for (qdcount = ntohs((unsigned short) hp->qdcount); 9927c478bd9Sstevel@tonic-gate qdcount--; 9937c478bd9Sstevel@tonic-gate ap += ret + QFIXEDSZ) 9947c478bd9Sstevel@tonic-gate { 9957c478bd9Sstevel@tonic-gate if ((ret = dn_skipname(ap, eom)) < 0) 9967c478bd9Sstevel@tonic-gate { 9977c478bd9Sstevel@tonic-gate if (tTd(8, 20)) 9987c478bd9Sstevel@tonic-gate sm_dprintf("qdcount failure (%d)\n", 9997c478bd9Sstevel@tonic-gate ntohs((unsigned short) hp->qdcount)); 10007c478bd9Sstevel@tonic-gate *statp = EX_SOFTWARE; 10017c478bd9Sstevel@tonic-gate return false; /* ???XXX??? */ 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate amatch = false; 10067c478bd9Sstevel@tonic-gate for (ancount = ntohs((unsigned short) hp->ancount); 10077c478bd9Sstevel@tonic-gate --ancount >= 0 && ap < eom; 10087c478bd9Sstevel@tonic-gate ap += n) 10097c478bd9Sstevel@tonic-gate { 10107c478bd9Sstevel@tonic-gate n = dn_expand((unsigned char *) &answer, eom, ap, 1011*058561cbSjbeck (RES_UNC_T) nbuf, sizeof(nbuf)); 10127c478bd9Sstevel@tonic-gate if (n < 0) 10137c478bd9Sstevel@tonic-gate break; 10147c478bd9Sstevel@tonic-gate ap += n; 10157c478bd9Sstevel@tonic-gate GETSHORT(type, ap); 10167c478bd9Sstevel@tonic-gate ap += INT16SZ; /* skip over class */ 10177c478bd9Sstevel@tonic-gate GETLONG(ttl, ap); 10187c478bd9Sstevel@tonic-gate GETSHORT(n, ap); /* rdlength */ 10197c478bd9Sstevel@tonic-gate switch (type) 10207c478bd9Sstevel@tonic-gate { 10217c478bd9Sstevel@tonic-gate case T_MX: 10227c478bd9Sstevel@tonic-gate gotmx = true; 10237c478bd9Sstevel@tonic-gate if (**dp != '\0' && HasWildcardMX) 10247c478bd9Sstevel@tonic-gate { 10257c478bd9Sstevel@tonic-gate /* 10267c478bd9Sstevel@tonic-gate ** If we are using MX matches and have 10277c478bd9Sstevel@tonic-gate ** not yet gotten one, save this one 10287c478bd9Sstevel@tonic-gate ** but keep searching for an A or 10297c478bd9Sstevel@tonic-gate ** CNAME match. 10307c478bd9Sstevel@tonic-gate */ 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate if (trymx && mxmatch == NULL) 10337c478bd9Sstevel@tonic-gate mxmatch = *dp; 10347c478bd9Sstevel@tonic-gate continue; 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate /* 10387c478bd9Sstevel@tonic-gate ** If we did not append a domain name, this 10397c478bd9Sstevel@tonic-gate ** must have been a canonical name to start 10407c478bd9Sstevel@tonic-gate ** with. Even if we did append a domain name, 10417c478bd9Sstevel@tonic-gate ** in the absence of a wildcard MX this must 10427c478bd9Sstevel@tonic-gate ** still be a real MX match. 10437c478bd9Sstevel@tonic-gate ** Such MX matches are as good as an A match, 10447c478bd9Sstevel@tonic-gate ** fall through. 10457c478bd9Sstevel@tonic-gate */ 10467c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate # if NETINET6 10497c478bd9Sstevel@tonic-gate case T_AAAA: 10507c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 10517c478bd9Sstevel@tonic-gate case T_A: 10527c478bd9Sstevel@tonic-gate /* Flag that a good match was found */ 10537c478bd9Sstevel@tonic-gate amatch = true; 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* continue in case a CNAME also exists */ 10567c478bd9Sstevel@tonic-gate continue; 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate case T_CNAME: 10597c478bd9Sstevel@tonic-gate if (DontExpandCnames) 10607c478bd9Sstevel@tonic-gate { 10617c478bd9Sstevel@tonic-gate /* got CNAME -- guaranteed canonical */ 10627c478bd9Sstevel@tonic-gate amatch = true; 10637c478bd9Sstevel@tonic-gate break; 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate if (loopcnt++ > MAXCNAMEDEPTH) 10677c478bd9Sstevel@tonic-gate { 10687c478bd9Sstevel@tonic-gate /*XXX should notify postmaster XXX*/ 10697c478bd9Sstevel@tonic-gate message("DNS failure: CNAME loop for %s", 10707c478bd9Sstevel@tonic-gate host); 10717c478bd9Sstevel@tonic-gate if (CurEnv->e_message == NULL) 10727c478bd9Sstevel@tonic-gate { 10737c478bd9Sstevel@tonic-gate char ebuf[MAXLINE]; 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate (void) sm_snprintf(ebuf, 1076*058561cbSjbeck sizeof(ebuf), 10777c478bd9Sstevel@tonic-gate "Deferred: DNS failure: CNAME loop for %.100s", 10787c478bd9Sstevel@tonic-gate host); 10797c478bd9Sstevel@tonic-gate CurEnv->e_message = 10807c478bd9Sstevel@tonic-gate sm_rpool_strdup_x( 10817c478bd9Sstevel@tonic-gate CurEnv->e_rpool, ebuf); 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate SM_SET_H_ERRNO(NO_RECOVERY); 10847c478bd9Sstevel@tonic-gate *statp = EX_CONFIG; 10857c478bd9Sstevel@tonic-gate return false; 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate /* value points at name */ 10897c478bd9Sstevel@tonic-gate if ((ret = dn_expand((unsigned char *)&answer, 10907c478bd9Sstevel@tonic-gate eom, ap, (RES_UNC_T) nbuf, 10917c478bd9Sstevel@tonic-gate sizeof(nbuf))) < 0) 10927c478bd9Sstevel@tonic-gate break; 10937c478bd9Sstevel@tonic-gate (void) sm_strlcpy(host, nbuf, hbsize); 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate /* 10967c478bd9Sstevel@tonic-gate ** RFC 1034 section 3.6 specifies that CNAME 10977c478bd9Sstevel@tonic-gate ** should point at the canonical name -- but 10987c478bd9Sstevel@tonic-gate ** urges software to try again anyway. 10997c478bd9Sstevel@tonic-gate */ 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate goto cnameloop; 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate default: 11047c478bd9Sstevel@tonic-gate /* not a record of interest */ 11057c478bd9Sstevel@tonic-gate continue; 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate if (amatch) 11107c478bd9Sstevel@tonic-gate { 11117c478bd9Sstevel@tonic-gate /* 11127c478bd9Sstevel@tonic-gate ** Got a good match -- either an A, CNAME, or an 11137c478bd9Sstevel@tonic-gate ** exact MX record. Save it and get out of here. 11147c478bd9Sstevel@tonic-gate */ 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate mxmatch = *dp; 11177c478bd9Sstevel@tonic-gate break; 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate /* 11217c478bd9Sstevel@tonic-gate ** Nothing definitive yet. 11227c478bd9Sstevel@tonic-gate ** If this was a T_A query and we haven't yet found a MX 11237c478bd9Sstevel@tonic-gate ** match, try T_MX if allowed to do so. 11247c478bd9Sstevel@tonic-gate ** Otherwise, try the next domain. 11257c478bd9Sstevel@tonic-gate */ 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate # if NETINET6 11287c478bd9Sstevel@tonic-gate if (qtype == T_AAAA) 11297c478bd9Sstevel@tonic-gate qtype = T_A; 11307c478bd9Sstevel@tonic-gate else 11317c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 11327c478bd9Sstevel@tonic-gate if (qtype == T_A && !gotmx && (trymx || **dp == '\0')) 11337c478bd9Sstevel@tonic-gate qtype = T_MX; 11347c478bd9Sstevel@tonic-gate else 11357c478bd9Sstevel@tonic-gate { 11367c478bd9Sstevel@tonic-gate qtype = initial; 11377c478bd9Sstevel@tonic-gate dp++; 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate /* if nothing was found, we are done */ 11427c478bd9Sstevel@tonic-gate if (mxmatch == NULL) 11437c478bd9Sstevel@tonic-gate { 11447c478bd9Sstevel@tonic-gate if (*statp == EX_OK) 11457c478bd9Sstevel@tonic-gate *statp = EX_NOHOST; 11467c478bd9Sstevel@tonic-gate return false; 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate /* 11507c478bd9Sstevel@tonic-gate ** Create canonical name and return. 11517c478bd9Sstevel@tonic-gate ** If saved domain name is null, name was already canonical. 11527c478bd9Sstevel@tonic-gate ** Otherwise append the saved domain name. 11537c478bd9Sstevel@tonic-gate */ 11547c478bd9Sstevel@tonic-gate 1155*058561cbSjbeck (void) sm_snprintf(nbuf, sizeof(nbuf), "%.*s%s%.*s", MAXDNAME, host, 11567c478bd9Sstevel@tonic-gate *mxmatch == '\0' ? "" : ".", 11577c478bd9Sstevel@tonic-gate MAXDNAME, mxmatch); 11587c478bd9Sstevel@tonic-gate (void) sm_strlcpy(host, nbuf, hbsize); 11597c478bd9Sstevel@tonic-gate if (tTd(8, 5)) 11607c478bd9Sstevel@tonic-gate sm_dprintf("dns_getcanonname: %s\n", host); 11617c478bd9Sstevel@tonic-gate *statp = EX_OK; 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate /* return only one TTL entry, that should be sufficient */ 11647c478bd9Sstevel@tonic-gate if (ttl > 0 && pttl != NULL) 11657c478bd9Sstevel@tonic-gate *pttl = ttl; 11667c478bd9Sstevel@tonic-gate return true; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 1169