📄 domain.c
字号:
/* * Copyright (c) 1986 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "sendmail.h"#ifndef lint#if NAMED_BINDstatic char sccsid[] = "@(#)domain.c 8.19 (Berkeley) 3/11/94 (with name server)";#elsestatic char sccsid[] = "@(#)domain.c 8.19 (Berkeley) 3/11/94 (without name server)";#endif#endif /* not lint */#if NAMED_BIND#include <errno.h>#include <arpa/nameser.h>#include <resolv.h>#include <netdb.h>typedef union{ HEADER qb1; char qb2[PACKETSZ];} querybuf;static char MXHostBuf[MAXMXHOSTS*PACKETSZ];#ifndef MAXDNSRCH#define MAXDNSRCH 6 /* number of possible domains to search */#endif#ifndef MAX#define MAX(a, b) ((a) > (b) ? (a) : (b))#endif#ifndef NO_DATA# define NO_DATA NO_ADDRESS#endif#ifndef HEADERSZ# define HEADERSZ sizeof(HEADER)#endif/* don't use sizeof because sizeof(long) is different on 64-bit machines */#define SHORTSIZE 2 /* size of a short (really, must be 2) */#define LONGSIZE 4 /* size of a long (really, must be 4) */#define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion *//*** GETMXRR -- get MX resource records for a domain**** Parameters:** host -- the name of the host to MX.** mxhosts -- a pointer to a return buffer of MX records.** droplocalhost -- If TRUE, all MX records less preferred** than the local host (as determined by $=w) will** be discarded.** rcode -- a pointer to an EX_ status code.**** Returns:** The number of MX records found.** -1 if there is an internal failure.** If no MX records are found, mxhosts[0] is set to host** and 1 is returned.*/getmxrr(host, mxhosts, droplocalhost, rcode) char *host; char **mxhosts; bool droplocalhost; int *rcode;{ extern int h_errno; register u_char *eom, *cp; register int i, j, n; int nmx = 0; register char *bp; HEADER *hp; querybuf answer; int ancount, qdcount, buflen; bool seenlocal = FALSE; u_short pref, localpref, type; char *fallbackMX = FallBackMX; static bool firsttime = TRUE; STAB *st; bool trycanon = FALSE; u_short prefer[MAXMXHOSTS]; int weight[MAXMXHOSTS]; extern bool getcanonname(); if (tTd(8, 2)) printf("getmxrr(%s, droplocalhost=%d)\n", host, droplocalhost); if (fallbackMX != NULL) { if (firsttime && res_query(FallBackMX, C_IN, T_A, (char *) &answer, sizeof answer) < 0) { /* this entry is bogus */ fallbackMX = FallBackMX = NULL; } else if (droplocalhost && (st = stab(fallbackMX, ST_CLASS, ST_FIND)) != NULL && bitnset('w', st->s_class)) { /* don't use fallback for this pass */ fallbackMX = NULL; } firsttime = FALSE; } /* efficiency hack -- numeric or non-MX lookups */ if (host[0] == '[') goto punt; errno = 0; n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer)); if (n < 0) { if (tTd(8, 1)) printf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n", (host == NULL) ? "<NULL>" : host, errno, h_errno); switch (h_errno) { case NO_DATA: trycanon = TRUE; /* fall through */ case NO_RECOVERY: /* no MX data on this host */ goto punt; case HOST_NOT_FOUND:#ifdef BROKEN_RES_SEARCH /* Ultrix resolver returns failure w/ h_errno=0 */ case 0:#endif /* the host just doesn't exist */ *rcode = EX_NOHOST; if (!UseNameServer) { /* might exist in /etc/hosts */ goto punt; } break; case TRY_AGAIN: /* couldn't connect to the name server */ if (!UseNameServer && errno == ECONNREFUSED) goto punt; /* it might come up later; better queue it up */ *rcode = EX_TEMPFAIL; break; default: syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)\n", host, h_errno); *rcode = EX_OSERR; break; } /* irreconcilable differences */ return (-1); } /* find first satisfactory answer */ hp = (HEADER *)&answer; cp = (u_char *)&answer + HEADERSZ; eom = (u_char *)&answer + n; for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) if ((n = dn_skipname(cp, eom)) < 0) goto punt; buflen = sizeof(MXHostBuf) - 1; bp = MXHostBuf; ancount = ntohs(hp->ancount); while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1) { if ((n = dn_expand((u_char *)&answer, eom, cp, (u_char *)bp, buflen)) < 0) break; cp += n; GETSHORT(type, cp); cp += SHORTSIZE + LONGSIZE; GETSHORT(n, cp); if (type != T_MX) { if (tTd(8, 8) || _res.options & RES_DEBUG) printf("unexpected answer type %d, size %d\n", type, n); cp += n; continue; } GETSHORT(pref, cp); if ((n = dn_expand((u_char *)&answer, eom, cp, (u_char *)bp, buflen)) < 0) break; cp += n; if (droplocalhost && (st = stab(bp, ST_CLASS, ST_FIND)) != NULL && bitnset('w', st->s_class)) { if (tTd(8, 3)) printf("found localhost (%s) in MX list, pref=%d\n", bp, pref); if (!seenlocal || pref < localpref) localpref = pref; seenlocal = TRUE; continue; } weight[nmx] = mxrand(bp); prefer[nmx] = pref; mxhosts[nmx++] = bp; n = strlen(bp); bp += n; if (bp[-1] != '.') { *bp++ = '.'; n++; } *bp++ = '\0'; buflen -= n + 1; } /* sort the records */ for (i = 0; i < nmx; i++) { for (j = i + 1; j < nmx; j++) { if (prefer[i] > prefer[j] || (prefer[i] == prefer[j] && weight[i] > weight[j])) { register int temp; register char *temp1; temp = prefer[i]; prefer[i] = prefer[j]; prefer[j] = temp; temp1 = mxhosts[i]; mxhosts[i] = mxhosts[j]; mxhosts[j] = temp1; temp = weight[i]; weight[i] = weight[j]; weight[j] = temp; } } if (seenlocal && prefer[i] >= localpref) { /* truncate higher preference part of list */ nmx = i; } } if (nmx == 0) {punt: if (seenlocal && (!TryNullMXList || gethostbyname(host) == NULL)) { /* ** If we have deleted all MX entries, this is ** an error -- we should NEVER send to a host that ** has an MX, and this should have been caught ** earlier in the config file. ** ** Some sites prefer to go ahead and try the ** A record anyway; that case is handled by ** setting TryNullMXList. I believe this is a ** bad idea, but it's up to you.... */ *rcode = EX_CONFIG; syserr("MX list for %s points back to %s", host, MyHostName); return -1; } strcpy(MXHostBuf, host); mxhosts[0] = MXHostBuf; if (host[0] == '[') { register char *p; /* this may be an MX suppression-style address */ p = strchr(MXHostBuf, ']'); if (p != NULL) { *p = '\0'; if (inet_addr(&MXHostBuf[1]) != -1) *p = ']'; else { trycanon = TRUE; mxhosts[0]++; } } } if (trycanon && getcanonname(mxhosts[0], sizeof MXHostBuf - 2, FALSE)) { bp = &MXHostBuf[strlen(MXHostBuf)]; if (bp[-1] != '.') { *bp++ = '.'; *bp = '\0'; } } nmx = 1; } /* if we have a default lowest preference, include that */ if (fallbackMX != NULL && !seenlocal) mxhosts[nmx++] = fallbackMX; return (nmx);}/*** MXRAND -- create a randomizer for equal MX preferences**** If two MX hosts have equal preferences we want to randomize** the selection. But in order for signatures to be the same,** we need to randomize the same way each time. This function** computes a pseudo-random hash function from the host name.**** Parameters:** host -- the name of the host.**** Returns:** A random but repeatable value based on the host name.**** Side Effects:** none.*/mxrand(host) register char *host;{ int hfunc; static unsigned int seed; if (seed == 0) { seed = (int) curtime() & 0xffff; if (seed == 0) seed++; } if (tTd(17, 9)) printf("mxrand(%s)", host); hfunc = seed; while (*host != '\0') {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -