This is a discussion on Linux free port allocation algorithm within the Linux Networking forums, part of the Linux Forums category; There seems to have been a change in the Linux free port allocation algorithm somewhere between kernel 2.6.9 ...
|
|||||||
| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
|
|||
|
There seems to have been a change in the Linux free port allocation
algorithm somewhere between kernel 2.6.9 and 2.6.17. When a socket is allocated (with the bind() system call) with sin_port = 0 in 2.6.9 it seems that free ports are handed out sequentially, while 2.6.17 will hand them out in random order. Unfortunately this breaks a program I use, which depends on being able to allocate a port, free it and then allocate it again shortly thereafter; if ports are handed out randomly and there are several programs on the machine doing the same thing the allocation will fail fairly often (this is the birthday paradox). Does anyone know when the algorithm was changed? Is there a way to restore the old behavior in newer kernels? Thanks! |
|
|||
|
kreide@gmail.com writes:
>There seems to have been a change in the Linux free port allocation >algorithm somewhere between kernel 2.6.9 and 2.6.17. >When a socket is allocated (with the bind() system call) with >sin_port = 0 in 2.6.9 it seems that free ports are handed out >sequentially, while 2.6.17 will hand them out in random order. >Unfortunately this breaks a program I use, which depends on being able Well, then that program should be changed. It has a bug in it. >to allocate a port, free it and then allocate it again shortly >thereafter; if ports are handed out randomly and there are several >programs on the machine doing the same thing the allocation will fail >fairly often (this is the birthday paradox). Have you found such failures or are you just guessing? >Does anyone know when the algorithm was changed? Is there a way to >restore the old behavior in newer kernels? |
|
|||
|
> >Unfortunately this breaks a program I use, which depends on being able
> Well, then that program should be changed. It has a bug in it. I agree, however, I do not have the option of changing the program in question, thus unless I can find a way to preserve the old behavior on newer kernels I am stuck with 2.6.9. > >programs on the machine doing the same thing the allocation will fail > >fairly often (this is the birthday paradox). > Have you found such failures or are you just guessing? Yes, unfortunately this does happen in practice, which is why I am trying to find a solution. |
|
|||
|
On Jan 5, 1:22 pm, kre...@gmail.com wrote:
> Yes, unfortunately this does happen in practice, which is why I am > trying to find a solution. Preload a library that changes the 'bind' wrapper so that a 'bind' with a port of zero uses a port that you select using whatever algorithm you like. Google for 'LD_PRELOAD' for more information. DS |
|
|||
|
On Jan 5, 1:22 pm, kre...@gmail.com wrote:
> Yes, unfortunately this does happen in practice, which is why I am > trying to find a solution. David Schwartz <davids@webmaster.com> wrote: > Preload a library that changes the 'bind' wrapper so that a 'bind' > with a port of zero uses a port that you select using whatever > algorithm you like. Alternatively, change your program (since that's the one with the incorrect expectation) to give bind() a specific port number. Chris |
|
|||
|
Hello,
kreide@gmail.com a écrit : > There seems to have been a change in the Linux free port allocation > algorithm somewhere between kernel 2.6.9 and 2.6.17. > > When a socket is allocated (with the bind() system call) with > sin_port = 0 in 2.6.9 it seems that free ports are handed out > sequentially, while 2.6.17 will hand them out in random order. [cut description of application with broken behaviour] > Does anyone know when the algorithm was changed? 2.6.11 : [TCP]: Efficient port randomization Provide port randomization for incoming connections using variation of existing sequence number hash. 2.6.15 : [TCP/DCCP]: Randomize port selection This patch randomizes the port selected on bind() for connections to help with possible security attacks. It should also be faster in most cases because there is no need for a global lock. > Is there a way to restore the old behavior in newer kernels? I haven't found any sysctl which does that. |
|
|||
|
> Preload a library that changes the 'bind' wrapper so that a 'bind'
In case someone else is interested I am posting the source code for the program that I came up with. It has been a while since I did low- level C programming, but hopefully someone here can do a code review and point out any flaws or suggest improvements. #include <stdio.h> #include <errno.h> // avoid duplicate definition of bind() #define _SYS_SOCKET_H 1 #include <netinet/in.h> // required to get RTLD_NEXT #ifndef __USE_GNU #define __USE_GNU 1 #endif #include <dlfcn.h> #define LOW_PORT 32768 #define HIGH_PORT 60999 volatile static int next_port = LOW_PORT; int bind(int __fd, struct sockaddr * __addr, socklen_t __len) { static off_t (*funcptr)(int, struct sockaddr *, socklen_t) = NULL; if (!funcptr) { funcptr = (off_t (*)(int, struct sockaddr *, socklen_t)) dlsym(RTLD_NEXT, "bind"); } if ( __addr->sa_family == AF_INET) { struct sockaddr_in * __addr_in = (struct sockaddr_in *) __addr; if (__addr_in->sin_port == 0) { int ret; do { if (next_port > HIGH_PORT) next_port = LOW_PORT; int my_port = next_port++; __addr_in->sin_port = htons(my_port); ret = (*funcptr)(__fd, __addr, __len); } while (ret < 0 && errno == EADDRINUSE); return ret; } } return (*funcptr)(__fd, __addr, __len); } |
|
|||
|
> [cut description of application with broken behavior]
Let me quickly describe why I need this; it is not as unreasonable as one might think. I have several server modules which are unit tested automatically; my testing tool is integrated with the RCS (mercurial in case anyone is curious) which checks out and tests all committed revisions. Since the testing is somewhat time consuming and the machine has lots of spare CPU cores many revisions are tested in parallel. Some of the server modules are 3rd party and require a port number to be specified when they are started; since many instances of each server module is running on the same machine they need different port numbers and the way I obtain these is by allocating a socket on a free port, close the socket and give that port number to the server module. There is of course a race condition here, but if free ports are handed out sequentially this is not a problem in practice; if they are random it is. Changing the 3rd party modules is unfortunately not an option, and I would like to avoid having to implement my own service to keep track of allocated ports on the machine; depending on bind() behaving in a certain way seems like the better option. |
|
|||
|
On Jan 7, 9:51 am, kre...@gmail.com wrote:
> Some of the server modules are 3rd party and require a port number to > be specified when they are started; since many instances of each > server module is running on the same machine they need different port > numbers and the way I obtain these is by allocating a socket on a free > port, close the socket and give that port number to the server module. > There is of course a race condition here, but if free ports are handed > out sequentially this is not a problem in practice; if they are random > it is. A better solution, IMO, is to use a range of ports that is outside the range the system assigns from. So if the system assigns from, say, 33,000 to 55,000, you assign from 60,000 up sequentially, wrapping around if you run out. You don't seem to have any need for system-assigned port numbers here. DS |