From Bugzilla Helper: User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021003 Description of problem: When all the reserved ports below 512 are already in use and you pass a suggested port number below 512 to rresvport then rresvport will assign you a non-reserved port. Version-Release number of selected component (if applicable): How reproducible: Always Steps to Reproduce: 1.write a program that calls rresvport 513 times with a parameter less than 512 Actual Results: a non reserved port Expected Results: -1 & errno set to EAGAIN Additional info:
The bug is easy to see in rresvport: In glibc/inet/rcmd.c in the function rresvport_af: 454 for (;;) { 455 *sport = htons((uint16_t) *alport); 456 if (bind(s, (struct sockaddr *)&ss, len) >= 0) 457 return s; 458 if (errno != EADDRINUSE) { 459 (void)__close(s); 460 return -1; 461 } 462 (*alport)--; 463 if (*alport == IPPORT_RESERVED/2) 464 break; 465 } In line 463 you can see that if you pass a port number < IPPORT_RESERVED/2 into the function the loop doesn't terminate and *alport can become less than 0 in which case a non reserved port is assigned. An appropriate fix may be something like: if (*alport == IPPORT_RESERVED/2 || *alport < 0 )
E.g. http://www.mkssoftware.com/docs/man3/rcmd.3.asp documents that the caller must pass an argument between 512 and 1023 inclusive. Likewise http://conx.bu.edu/cgi-bin/perl/manscript?ruserok(3) Don't know if it wouldn't be better to add if (*alport < IPPORT_RESERVED / 2 || *alport >= IPPORT_RESERVED) { errno = EINVAL; return -1; } early in the function (and change (*alport)--; if (*alport == IPPORT_RESERVED/2) to if ((*alport--) == IPPORT_RESERVED / 2) so that a) it is possible to call rresvport with *alpost == 512 and it tries even port 512.
Traditional BSD behavior (rresvport is a 4.2BSD invention) tries the given port value and if that exact port is not available it ignores it and selects without regard to the original value. Hence some traditional callers might not even initialize the value. Such uses might already be broken, but I am leary of adding a new errno return that wasn't possible before.
Ok, then what about instead of errno = EINVAL; return -1; just *alport = 1023; ? Binding ports in 0 .. 511 area is a bad idea, since legitimate services could not be started later on due the port taken by rresvport.
By the currently documented spec, returning EAGAIN is ok. Wrapping up to 1023 seems fine to me.
I've checked in a change which normalizes the input and wraps around after looking at port 512. int/rcmd.c revision 1.64.
glibc 2.3.2-27.9 should behave as we intend it to. If this is still not what you want you might have to adjust your expectations. Give it a try.