|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T d
Length: 16443 (0x403b) Types: TextFile Names: »domain.c,v«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit └─⟦bfebc70e2⟧ »EurOpenD3/mail/sendmail-5.65b+IDA-1.4.3.tar.Z« └─⟦f9e35cd84⟧ └─⟦this⟧ »sendmail/src/RCS/domain.c,v«
head 5.22; branch 5.22.0; access; symbols UICSO:5.22.0 VANILLA:5.22; locks; strict; comment @ * @; 5.22 date 90.06.20.08.35.43; author paul; state Exp; branches 5.22.0.1; next ; 5.22.0.1 date 90.06.20.09.42.56; author paul; state Exp; branches; next 5.22.0.2; 5.22.0.2 date 90.08.02.12.45.58; author paul; state Exp; branches; next 5.22.0.3; 5.22.0.3 date 90.08.10.14.48.49; author paul; state Exp; branches; next 5.22.0.4; 5.22.0.4 date 90.09.21.07.45.05; author paul; state Exp; branches; next 5.22.0.5; 5.22.0.5 date 90.10.13.18.21.20; author paul; state Exp; branches; next 5.22.0.6; 5.22.0.6 date 90.10.16.22.49.35; author paul; state Exp; branches; next 5.22.0.7; 5.22.0.7 date 90.11.01.17.17.04; author paul; state Exp; branches; next 5.22.0.8; 5.22.0.8 date 90.11.26.20.40.41; author paul; state Exp; branches; next 5.22.0.9; 5.22.0.9 date 91.03.04.21.48.23; author paul; state Exp; branches; next ; desc @@ 5.22 log @5.64 Berkeley release @ text @/* * Copyright (c) 1986 Eric P. Allman * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted provided * that: (1) source distributions retain this entire copyright notice and * comment, and (2) distributions including binaries display the following * acknowledgement: ``This product includes software developed by the * University of California, Berkeley and its contributors'' in the * documentation or other materials provided with the distribution and in * all advertising materials mentioning features or use of this software. * 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include "sendmail.h" #ifndef lint #ifdef NAMED_BIND static char sccsid[] = "@@(#)domain.c 5.22 (Berkeley) 6/1/90 (with name server)"; #else static char sccsid[] = "@@(#)domain.c 5.22 (Berkeley) 6/1/90 (without name server)"; #endif #endif /* not lint */ #ifdef NAMED_BIND #include <sys/param.h> #include <errno.h> #include <arpa/nameser.h> #include <resolv.h> #include <netdb.h> typedef union { HEADER qb1; char qb2[PACKETSZ]; } querybuf; static char hostbuf[MAXMXHOSTS*PACKETSZ]; getmxrr(host, mxhosts, localhost, rcode) char *host, **mxhosts, *localhost; int *rcode; { extern int h_errno; register u_char *eom, *cp; register int i, j, n, nmx; register char *bp; HEADER *hp; querybuf answer; int ancount, qdcount, buflen, seenlocal; u_short pref, localpref, type, prefer[MAXMXHOSTS]; 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 failed (errno=%d, h_errno=%d)\n", errno, h_errno); switch (h_errno) { case NO_DATA: case NO_RECOVERY: /* no MX data on this host */ goto punt; case HOST_NOT_FOUND: /* the host just doesn't exist */ *rcode = EX_NOHOST; 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; } /* irreconcilable differences */ return (-1); } /* find first satisfactory answer */ hp = (HEADER *)&answer; cp = (u_char *)&answer + sizeof(HEADER); eom = (u_char *)&answer + n; for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) if ((n = dn_skipname(cp, eom)) < 0) goto punt; nmx = 0; seenlocal = 0; buflen = sizeof(hostbuf); bp = hostbuf; ancount = ntohs(hp->ancount); while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS) { if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) break; cp += n; GETSHORT(type, cp); cp += sizeof(u_short) + sizeof(u_long); GETSHORT(n, cp); if (type != T_MX) { if (tTd(8, 1) || _res.options & RES_DEBUG) printf("unexpected answer type %d, size %d\n", type, n); cp += n; continue; } GETSHORT(pref, cp); if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) break; cp += n; if (!strcasecmp(bp, localhost)) { if (seenlocal == 0 || pref < localpref) localpref = pref; seenlocal = 1; continue; } prefer[nmx] = pref; mxhosts[nmx++] = bp; n = strlen(bp) + 1; bp += n; buflen -= n; } if (nmx == 0) { punt: mxhosts[0] = strcpy(hostbuf, host); return(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] && rand() % 1 == 0)) { 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; } } if (seenlocal && prefer[i] >= localpref) { /* * truncate higher pref part of list; if we're * the best choice left, we should have realized * awhile ago that this was a local delivery. */ if (i == 0) { *rcode = EX_CONFIG; return(-1); } nmx = i; break; } } return(nmx); } getcanonname(host, hbsize) char *host; int hbsize; { extern int h_errno; register u_char *eom, *cp; register int n; HEADER *hp; querybuf answer; u_short type; int first, ancount, qdcount, loopcnt; char nbuf[PACKETSZ]; loopcnt = 0; loop: /* * Use query type of ANY if possible (NO_WILDCARD_MX), which will * find types CNAME, A, and MX, and will cause all existing records * to be cached by our local server. If there is (might be) a * wildcard MX record in the local domain or its parents that are * searched, we can't use ANY; it would cause fully-qualified names * to match as names in a local domain. */ # ifdef NO_WILDCARD_MX n = res_search(host, C_IN, T_ANY, (char *)&answer, sizeof(answer)); # else n = res_search(host, C_IN, T_CNAME, (char *)&answer, sizeof(answer)); # endif if (n < 0) { if (tTd(8, 1)) printf("getcanonname: res_search failed (errno=%d, h_errno=%d)\n", errno, h_errno); return; } /* find first satisfactory answer */ hp = (HEADER *)&answer; ancount = ntohs(hp->ancount); /* we don't care about errors here, only if we got an answer */ if (ancount == 0) { if (tTd(8, 1)) printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); return; } cp = (u_char *)&answer + sizeof(HEADER); eom = (u_char *)&answer + n; for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) if ((n = dn_skipname(cp, eom)) < 0) return; /* * just in case someone puts a CNAME record after another record, * check all records for CNAME; otherwise, just take the first * name found. */ for (first = 1; --ancount >= 0 && cp < eom; cp += n) { if ((n = dn_expand((char *)&answer, eom, cp, nbuf, sizeof(nbuf))) < 0) break; if (first) { /* XXX */ (void)strncpy(host, nbuf, hbsize); host[hbsize - 1] = '\0'; first = 0; } cp += n; GETSHORT(type, cp); cp += sizeof(u_short) + sizeof(u_long); GETSHORT(n, cp); if (type == T_CNAME) { /* * assume that only one cname will be found. More * than one is undefined. Copy so that if dn_expand * fails, `host' is still okay. */ if ((n = dn_expand((char *)&answer, eom, cp, nbuf, sizeof(nbuf))) < 0) break; (void)strncpy(host, nbuf, hbsize); /* XXX */ host[hbsize - 1] = '\0'; if (++loopcnt > 8) /* never be more than 1 */ return; goto loop; } } } #else /* not NAMED_BIND */ #include <netdb.h> getcanonname(host, hbsize) char *host; int hbsize; { struct hostent *hp; hp = gethostbyname(host); if (hp == NULL) return; if (strlen(hp->h_name) >= hbsize) return; (void) strcpy(host, hp->h_name); } #endif /* not NAMED_BIND */ @ 5.22.0.1 log @IDA patches @ text @a43 1 extern int h_errno; d50 1 a67 3 #ifndef NO_DATA # define NO_DATA NO_ADDRESS #endif NO_DATA a171 40 /* ** Getcanonname() below is broken in the sense that it won't return ** unqualified local host names with their full domain extension, ** unless the argument is an alias. ** ** Since gethostbyname() calls the name server with bind 4.8, ** I don't see why this function would be needed at all. I've ** therefore restored the old code in maphostname() of daemon.c ** that uses gethostbyname(). If there's something I've missed, ** feel free to change maphostname() to again call getcanonname(), ** but also make sure that the latter will qualify the host with ** its full domain AND return a status code indicating if the host ** was found. ** ** Lennart Lovstrand, Rank Xerox EuroPARC, 24-Aug-88 ** ** Unfortunately, just using gethostbyname won't do it. It queries for ** and returns only A Resource Records, so it will miss a host with only ** an MX record listed. If you're trying to deliver everything you can ** via the Internet, and deliver to only those hosts who are not in the ** domain name system at all by a "smart UUCP" mailer like smail, you ** will end up delivering more than you want to via that smart mailer. ** In that case, gethostbyname isn't enough. ** ** Chet Ramey, Case Western Reserve University, 15-Sep-88 ** ** Changed to make it return FALSE on an error, TRUE if an answer was ** found (any answer is enough). ** ** Chet Ramey, Case Western Reserve University, 16-Sep-88 ** ** In the case of a host with a MX record pointing at localhost, ** another routing method must be used. Examine any MX RRs returned. ** If the best one points to localhost, return FALSE. ** ** Paul Pomes, University of Illinois, 10-Oct-88 */ /* #ifdef GETHOSTBYNAME_ISNT_ENOUGH */ a183 4 u_short MailPreference = 1000; char MailAgent[MAXNAME]; char MyName[MAXNAME]; char **MyAliases; a184 4 extern char **myhostname(); MailAgent[0] = '\0'; d204 1 a204 1 return FALSE; d215 1 a215 1 return FALSE; d221 1 a221 1 return FALSE; d228 1 a228 1 for (first = 1; --ancount >= 0 && cp < eom; ) { a249 1 cp += n; d253 1 a253 1 return FALSE; a255 20 else if (type == T_MX) { /* * Be sure that the best MX record doesn't point * to the local machine. If it does, some other * delivery method is assumed. */ u_short preference; GETSHORT(preference, cp); if ((n = dn_expand((char *)&answer, eom, cp, nbuf, sizeof(nbuf))) < 0) break; cp += n; if (tTd(8, 1)) printf("getcanonname: MX host %s, preference %d\n", nbuf, preference); if (preference < MailPreference) { MailPreference = preference; (void) strcpy(MailAgent, nbuf); a256 15 } else cp += n; } if (MailAgent[0] != '\0' && (MyAliases = myhostname(MyName, MAXNAME)) != NULL) { if (strcasecmp(MailAgent, MyName) == 0) return FALSE; for (; *MyAliases != NULL; MyAliases++) if (strcasecmp(MailAgent, *MyAliases) == 0) return FALSE; return TRUE; } else return TRUE; a257 3 /* #endif GETHOSTBYNAME_ISNT_ENOUGH */ @ 5.22.0.2 log @Add comparison for a local MX record to test MailAgent against $j. Suggested by Neil Rickert, NIU. @ text @a332 6 /* test MailAgent against $j */ if (MailAgent[0] != '\0' && MyHostName != NULL && strcasecmp(MailAgent, MyHostName) == 0) return (FALSE); /* test MailAgent against our DNS name and aliases */ @ 5.22.0.3 log @Handle case of #undef NO_WILDCARD_MX with a relay host. @ text @d164 4 a167 2 if (i == 0) goto punt; d212 3 d351 3 @ 5.22.0.4 log @To: "Mark D. Baushke" <mdb@@kosciusko.esd.3com.com> Cc: Paul Pomes <Paul-Pomes@@uiuc.edu> Subject: Experimental changes to 'sendmail' Date: Tue, 18 Sep 90 10:04:39 -0500 From: rickert@@cs.niu.edu Basically they change the way that sendmail functions when 'NO_WILDCARD_MX' is not defined. I believe this is the way you have your system setup. Prior to this change, because of possible problems with wildcards, the code in getcanonname() only looked for CNAME and A records. With the NO_WILDCARD_MX defined, it looked also for MX records. With the change, MX records are always looked for. The difference is that where there is a concern about wildcard MX records, addresses are not qualified in the local domain. I believe the previous code, looking for CNAME and A records only, was superfluous, since the gethostbyname() call in daemon.c which precedes the call to getcanonname() already does this. So far it passes all my tests. It behaves almost exactly as if NO_WILDCARD_MX was defined, except that MX-only addresses are never qualified in the local domain. Domain names with A-records and CNAME records are qualified as before. (I haven't looked at a CNAME record for which there is no corresponding A-record). Provided that these addresses are qualified with DOMAINTABLE there should be no difference. In fact I am considering undefining NO_WILDCARD_MX for my production version of sendmail now because of the extra robustness of not having to remember to never create wildcard MX records. (Not actually a problem here since I control both sendmail and the domain records). -Neil Rickert @ text @d241 1 a241 3 # ifndef NO_WILDCARD_MX _res.options &= ( ~RES_DEFNAMES & 0xffff ) ; # endif d243 2 a244 2 # ifndef NO_WILDCARD_MX _res.options |= RES_DEFNAMES ; @ 5.22.0.5 log @Cleaned up #statements. @ text @d24 1 a24 1 # ifdef NAMED_BIND d26 1 a26 1 # else /* !NAMED_BIND */ d28 1 a28 1 # endif /* NAMED_BIND */ d33 5 a37 5 # include <sys/param.h> # include <errno.h> # include <arpa/nameser.h> # include <resolv.h> # include <netdb.h> d68 3 a70 3 # ifndef NO_DATA # define NO_DATA NO_ADDRESS # endif /* NO_DATA */ d243 1 a243 1 # endif /* NO_WILDCARD_MX */ d247 1 a247 1 # endif /* NO_WILDCARD_MX */ d349 1 a349 1 #else /* !NAMED_BIND */ d351 1 a351 1 # include <netdb.h> d369 1 a369 1 #endif /* !NAMED_BIND */ @ 5.22.0.6 log @To: paul-pomes@@uiuc.edu Subject: sendmail-5.65 incorrectly handles MX records with equal precedence Date: Tue, 16 Oct 90 23:10:18 EDT From: "David Edelsohn" <edelsohn@@nova.npac.syr.edu> Description: I was just looking up the source to sendmail-5.61 to see why the mail load is not being evenly distributed between my two hosts pointed to by MX records with the same preference level. In domain.c: getmxrr(), the MX records are sorted by preference with a special case if the preferences are identical. The condition is as follows: if (prefer[i] > prefer[j] || (prefer[i] == prefer[j] && rand() % 1 == 0)) { ...SWAP ENTRIES... } Should not the test be (rand() & 01) or (rand() % 2)? (rand() % 1) is always 0! rand() is not guaranteed to be random in the lowest bits as random() is suppose to be, but even regularly alternating between swapping and not swapping would be better than always swapping when preferences are equal. Not only does rand() % 1 always return 0, not only does rand() & 1 alternate between 0 and 1 regularly at each call (as long as the load is balanced it doesn't really matter), but since sendmail is called directly by Mail, the random number generator is reset to the same value each time (for both rand() and random()), i.e there is no call to srandom() with the PID or time-of-day or some other seed. This appears to be the only use of a random number generator within sendmail so only one MX record of equal precedence will be used assuming that the records are always returned in the same order at each DNS resolver call. The only saving grace would be if a queued message has the MX host re-calculated by the daemonized sendmail if the message is ever queued, but with (rand % 1) this is irrelevent in sendmail-5.61. Fix: 1) Change "rand % 1" to "rand & 1" 2) No matter which random number generator is used (rand() or random()), use the appropriate seed initializer call during the initial startup (in main.c?). The seed must be set post-thaw. @ text @d146 1 a146 1 (prefer[i] == prefer[j] && (rand()/3 & 1) == 0)) { @ 5.22.0.7 log @Change initial value of MailPreference to (u_short) -1. @ text @d222 1 a222 1 u_short MailPreference = (u_short) -1; @ 5.22.0.8 log @Commented out un-needed assignment. @ text @d298 1 a298 1 /* cp += n; un-used -pbp */ @ 5.22.0.9 log @ANSIfied. @ text @d48 1 a48 2 const char *host, *localhost; char **mxhosts; a209 2 bool d226 2 @