This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Don't bind to registered ports in bindresvport


When bindresvport binds to a random port, there's a good chance it will
pick one already registered in services. That's bad since the point of
services is to define well known ports so random programs know which
ones to avoid. The current behavior causes lots of downstream bugs and
requires hacky solutions like running programs early in boot to bind to
desired ports and handing them off when the actual services start.

https://bugzilla.redhat.com/show_bug.cgi?id=103401

Let's just fix the problem at the source. On my fedora system, 295 of
the 541 ports between 512 and 1023 are unregistered. There's plenty of
space to pick a smarter port. If there are systems that require more
random ports than that, bindresvport is probably not the right API to
use.

2012-05-31  Dan Nicholson  <dbn.lists@gmail.com>

	* sunrpc/bindrsvprt.c (bindresvport): Before binding the port,
	make sure it's not registered in services.
---
 sunrpc/bindrsvprt.c |   19 ++++++++++++++++---
 1 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/sunrpc/bindrsvprt.c b/sunrpc/bindrsvprt.c
index d493c9f..8594b33 100644
--- a/sunrpc/bindrsvprt.c
+++ b/sunrpc/bindrsvprt.c
@@ -35,6 +35,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <netdb.h>
 
 /*
  * Bind a socket to a privileged IP port
@@ -74,15 +75,27 @@ bindresvport (int sd, struct sockaddr_in *sin)
 
   int nports = ENDPORT - startport + 1;
   int endport = ENDPORT;
+  struct servent serv, *s;
+  char buf[1024];
  again:
   for (i = 0; i < nports; ++i)
     {
       sin->sin_port = htons (port++);
       if (port > endport)
 	port = startport;
-      res = __bind (sd, sin, sizeof (struct sockaddr_in));
-      if (res >= 0 || errno != EADDRINUSE)
-	break;
+      __getservbyport_r (sin->sin_port, NULL, &serv, buf, sizeof (buf), &s);
+      if (s != NULL)
+	{
+	  /* This port is registered. Fake a return and try the next. */
+	  res = -1;
+          __set_errno (EADDRINUSE);
+	}
+      else
+	{
+	  res = __bind (sd, sin, sizeof (struct sockaddr_in));
+	  if (res >= 0 || errno != EADDRINUSE)
+	    break;
+	}
     }
 
   if (i == nports && startport != LOWPORT)
-- 
1.7.7.6


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]