[comp.mail.sendmail] sendmail-5.65 incorrectly handles MX records with equal precedence

edelsohn@nova.npac.syr.edu (David Edelsohn) (10/18/90)

	I originally noticed the problem in 5.61 and sent a message to
bugs-bsd, but the error is still present in 5.65.  I sent a bug report to
Paul Pomes at UIUC, his reply is appended after my description of the bug.

Description:

	While looking up the source to sendmail-5.61 to determine why the
mail load is not being evenly distributed between my two hosts pointed to
by MX records with the same preference level, I found the following bug.
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!  Also, rand() is not guaranteed to be random in the lowest bits
as random() is suppose to be.
	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 srand() or
srandom() with the PID or time-of-day.
	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 queued, but with
(rand % 1) this is irrelevent in sendmail-5.61.

Proposed Fixes:

	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?) after the thaw.
--------
Response from Paul Pomes (paul-pomes@uiuc.edu):

Your problem description is absolutely correct.  I changed the call to be
(rand()/3 & 1) which gives a nice irregular pattern of 0 and 1.  The call
to srand() was inserted in main.c and uses MotherPid as the seed.
--------
					David
===============================================================================
David Edelsohn                                          SCCS/Dept of Physics
INTERNET: edelsohn@nova.npac.Syr.EDU                    201 Physics Bldg/SU
                                                        Syracuse, NY 13244-1130
"It's only a dream away ..." -- from Time Bandits ending credits song
"... Nature cannot be fooled." -- Richard Feynman

jeffe@sandino.austin.ibm.com (Peter Jeffe 512.823.4091) (10/18/90)

In article <1990Oct17.135603.27002@rodan.acs.syr.edu> edelsohn@nova.npac.syr.edu (David Edelsohn) writes:
>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)?

Yes, and as you also point out it should be seeded first with srand[om]().
But there is an additional problem with the algorithm: it only randomizes
successive *pairs* of records with the same preference.  If there are more
than two records with the same preference, the first record after the sort
will always be one of the first two, etc.

The only way I can see around this "some hosts are more equal than others"
scenario is to have an additional sort key that is set to a random number,
but I'm not sure it's worth the trouble.  Any other ideas/comments?

-------------------------------------------------------------------------------
Peter Jeffe   ...uunet!cs.utexas.edu!ibmchs!auschs!sandino.austin.ibm.com!jeffe
        first they want a disclaimer, then they make you pee in a jar,
                   then they come for you in the night

matt@group-w.uchicago.edu (Matt Crawford) (10/19/90)

) The only way I can see around this "some hosts are more equal than others"
) scenario is to have an additional sort key that is set to a random number,
) but I'm not sure it's worth the trouble.  Any other ideas/comments?

The easiest thing to do would be to multply all MX preference values by
some number N, say 256, and add a random number in [0, N-1] to each.
Just make sure you can't overflow and everything will be groovy.
________________________________________________________
Matt Crawford	     		matt@oddjob.uchicago.edu