[fa.tcp-ip] 4.2bsd/rlogin/source port choices

tcp-ip@ucbvax.ARPA (07/16/85)

From: stanonik@nprdc.arpa (Ron Stanonik)

4.2bsd/rlogin's use of reserved ports for user authentication
seemed the cause of a little problem here.  While a user was
rlogin'ed from a sun to a vax, the sun crashed.  After the sun
rebooted the user was unable to rlogin to the vax (connection
timed out?), apparently because the vax still thought the previous
connection from the sun was established, and the sun was trying
to reuse the same reserved port.  (rlogin chooses the source port
from the first available port starting at 1023, working downward.)
Of course killing the login on the vax marked the connection closed
and cleared up the problem, but there must be a better/nonmanual
way.  Have we've overlooked a 4.2bsd mod which allows rlogin or
the tcp's to sort this out?

Thanks,

Ron Stanonik
stanonik@nprdc

tcp-ip@ucbvax.ARPA (07/17/85)

From: imagen!geof@su-shasta.ARPA


The TCP source port for rlogin should be chosen in a manner that makes
it unlikely for the same port to be reused twice in a row.  "Twice in a
row" includes the possibility that the ports will be chosen before and
after crashes, so a RAM counter is inappropriate.  4.2's apparent
method of grabbing closest port below 1024 that is not currently used
tends to choose the same port twice in a row with high probability in a
number of cases.  This algorithm is not suitable for choosing TCP port
numbers (Gosh, I hope the kernel does a better job!).

A better technique is to generate some random number in the right range
of ports each time a port number is needed, and regenerate another if
you fail.  A simple expediency is to use the low-order bits of a
millisecond clock.  A user process on Unix (with a one-second clock)
might use:

	long now;

	time(&now);
	sleep(1);
	port = htons( (now + getpid()) % 512) + 512 );

to get a number in the range [512,1024), or

	port = htons( (now + getpid()) | 0x8000 );

to get a port number in the "temporary" range.

- Geof

tcp-ip@ucbvax.ARPA (07/17/85)

From: imagen!geof@su-shasta.ARPA


The choices that I suggested are all things that I have done in
implementations of various protocols (which need to choose port numbers
for the same reason TCP does), and that have worked well.  I personally
think that low bits of clocks are more random than pseudo-random number
generators.  To get a really random number from a PRNG, you have to
seed it with a random number (egg or chicken?).  The obvious thing to
do is seed the PRNG with the clock.  Hmm....  why don't you just use
the clock...?

Using a clock also makes sense from a more theoretical point of view.
In most situations the times at which connection requests are made are
much more like independent random variables than anything else that a
program can get its hands on.  Especially when you have a fast clock.

Of course, any choice of port is actually put inside of a loop which
makes sure that the port is Currently unique.  You can't be sure of not
choosing the same port twice Sequentially unless you have hardware that
is stable across system crashes (hey, the clock is more likely to fit
that criterion than anything else, isn't it...?).  If "portChoice()"
chooses a port number using whatever algorithm you have in mind (but
"1023" is probably not a good algorithm), then you need one of the
following program fragments (sometimes this fragment is embodied in the
kernel, which is an excellent idea):

	i := portChoice();
	while portInUse(i) do
		i := i + 1;

		or

	i := portChoice();
	while portInUse(i) do
		i := portChoice();

The one to use depends on the nature of you portChoice() procedure.  If
it is based on a one second clock, then maybe the first program
fragment is better.  If it is based on a microsecond clock, then the
two are probably equivalent, but I like the second better, perhaps for
irrational reasons.  In any event, if you have a good portChoice()
algorithm, you will almost never go through the loop more than once,
and if you often go through it more than twice, rewrite portChoice,
because it isn't working as it should.

- Geof